├── .gitignore
├── .swift-version
├── .travis.yml
├── Dockerfile
├── Integration Tests
├── SwiftServer%20localhost.postman_environment.json
└── SwiftServer.postman_collection.json
├── LICENSE
├── Package.pins
├── Package.swift
├── README.md
├── Sources
├── SwiftServer
│ └── main.swift
└── SwiftServerLibrary
│ ├── CRUDMongoEndpoint.swift
│ ├── CRUDMongoHandler.swift
│ ├── CRUDMongoProvider.swift
│ └── ItemEndpoint.swift
├── Tests
├── LinuxMain.swift
└── SwiftServerLibraryTests
│ └── ItemTests.swift
├── docker-compose-ci.yml
├── docker-compose-common.yml
├── docker-compose-dev.yml
├── docker-compose-prod.yml
├── run-integration-tests.sh
└── swift+docker.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Xcode
4 | #
5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
6 |
7 | ## Build generated
8 | build/
9 | DerivedData/
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata/
21 |
22 | ## Other
23 | *.moved-aside
24 | *.xcuserstate
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | Packages/
40 | .build/
41 | *.xcodeproj
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.1
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: node_js
3 | node_js:
4 | - "4"
5 |
6 | services:
7 | - docker
8 |
9 | install:
10 | - docker --version
11 | - docker-compose --version
12 | - docker-compose -f docker-compose-ci.yml build
13 | - docker-compose -f docker-compose-ci.yml up -d
14 |
15 | before_script:
16 | - npm install -g newman
17 |
18 | script:
19 | - ./run-integration-tests.sh
20 |
21 | after_success:
22 | - if [ "$TRAVIS_BRANCH" == "master" ]; then
23 | docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD";
24 | docker tag choefele/swift-server-app choefele/swift-server-app:${TRAVIS_COMMIT::8}-$TRAVIS_BUILD_NUMBER;
25 | docker push choefele/swift-server-app;
26 | fi
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:3.1
2 | MAINTAINER Claus
3 |
4 | WORKDIR /app
5 |
6 | RUN apt-get update && apt-get install -y \
7 | libssl-dev \
8 | && rm -rf /var/lib/apt/lists/*
9 |
10 | COPY Package.swift ./
11 | RUN swift package fetch; exit 0
12 |
13 | EXPOSE 8090
14 |
15 | COPY Sources ./Sources
16 | COPY Tests ./Tests
17 | RUN swift test
18 | CMD ./.build/debug/SwiftServer
--------------------------------------------------------------------------------
/Integration Tests/SwiftServer%20localhost.postman_environment.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "7cc567d4-abb7-4958-d4ec-a72c3844f59a",
3 | "name": "SwiftServer localhost",
4 | "values": [
5 | {
6 | "key": "base_url",
7 | "type": "text",
8 | "value": "localhost:8090",
9 | "enabled": true
10 | }
11 | ],
12 | "timestamp": 1474226039665,
13 | "_postman_variable_scope": "environment",
14 | "_postman_exported_at": "2016-09-18T19:15:57.809Z",
15 | "_postman_exported_using": "Postman/4.7.1"
16 | }
--------------------------------------------------------------------------------
/Integration Tests/SwiftServer.postman_collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "f807269b-a362-48e1-9c20-93a283b090f1",
3 | "name": "SwiftServer",
4 | "description": "",
5 | "order": [
6 | "53702c95-6b93-dcee-e940-ffb951a90513",
7 | "f9556291-8c43-39ae-8792-801b9518c068",
8 | "baa6cff1-9b70-3ee2-c685-c50cea818e8c"
9 | ],
10 | "folders": [],
11 | "timestamp": 1474219392030,
12 | "owner": "",
13 | "public": false,
14 | "published": false,
15 | "requests": [
16 | {
17 | "id": "53702c95-6b93-dcee-e940-ffb951a90513",
18 | "headers": "",
19 | "url": "{{base_url}}/ping",
20 | "preRequestScript": null,
21 | "pathVariables": {},
22 | "method": "GET",
23 | "data": null,
24 | "dataMode": "params",
25 | "version": 2,
26 | "tests": "tests[\"Status code is 200\"] = responseCode.code === 200;\ntests[\"Body is correct\"] = responseBody === \"pong\";",
27 | "currentHelper": "normal",
28 | "helperAttributes": {},
29 | "time": 1474220487911,
30 | "name": "Ping",
31 | "description": "",
32 | "collectionId": "f807269b-a362-48e1-9c20-93a283b090f1",
33 | "responses": []
34 | },
35 | {
36 | "id": "baa6cff1-9b70-3ee2-c685-c50cea818e8c",
37 | "headers": "",
38 | "url": "{{base_url}}/items",
39 | "preRequestScript": null,
40 | "pathVariables": {},
41 | "method": "POST",
42 | "data": null,
43 | "dataMode": "params",
44 | "version": 2,
45 | "tests": "tests[\"Status code is 201\"] = responseCode.code === 201;\n\nvar jsonData = JSON.parse(responseBody);\ntests[\"Created item has ID\"] = jsonData.id !== null;",
46 | "currentHelper": "normal",
47 | "helperAttributes": {},
48 | "time": 1474223954276,
49 | "name": "Create item",
50 | "description": "",
51 | "collectionId": "f807269b-a362-48e1-9c20-93a283b090f1",
52 | "responses": []
53 | },
54 | {
55 | "id": "f9556291-8c43-39ae-8792-801b9518c068",
56 | "headers": "",
57 | "url": "{{base_url}}/items",
58 | "preRequestScript": null,
59 | "pathVariables": {},
60 | "method": "GET",
61 | "data": null,
62 | "dataMode": "params",
63 | "tests": "tests[\"Status code is 200\"] = responseCode.code === 200;\ntests[\"Response time is less than 200ms\"] = responseTime < 100;\n\nvar jsonData = JSON.parse(responseBody);\nvar schema = {\n \"type\": \"object\",\n \"required\": [ \"items\" ],\n \"properties\": {\n \"items\": { \n \"type\": \"array\" ,\n \"items\": {\n \"type\": \"object\",\n \"required\": [ \"id\" ],\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"minLength\": 24\n }\n }\n }\n }\n }\n};\ntests[\"Valid JSON data\"] = tv4.validate(jsonData, schema);\nif (tv4.error) {\n console.log(\"Validation failed: \", tv4.error);\n}",
64 | "currentHelper": "normal",
65 | "helperAttributes": {},
66 | "time": 1474226034849,
67 | "name": "Read items",
68 | "description": "",
69 | "collectionId": "f807269b-a362-48e1-9c20-93a283b090f1",
70 | "responses": []
71 | }
72 | ]
73 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Claus Höfele
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.pins:
--------------------------------------------------------------------------------
1 | {
2 | "autoPin": true,
3 | "pins": [
4 | {
5 | "package": "BSON",
6 | "reason": null,
7 | "repositoryURL": "https://github.com/OpenKitten/BSON.git",
8 | "version": "5.1.4"
9 | },
10 | {
11 | "package": "CCurl",
12 | "reason": null,
13 | "repositoryURL": "https://github.com/IBM-Swift/CCurl.git",
14 | "version": "0.4.0"
15 | },
16 | {
17 | "package": "Cheetah",
18 | "reason": null,
19 | "repositoryURL": "https://github.com/OpenKitten/Cheetah.git",
20 | "version": "1.0.3"
21 | },
22 | {
23 | "package": "CryptoKitten",
24 | "reason": null,
25 | "repositoryURL": "https://github.com/OpenKitten/CryptoKitten.git",
26 | "version": "0.2.1"
27 | },
28 | {
29 | "package": "Environment",
30 | "reason": null,
31 | "repositoryURL": "https://github.com/Danappelxx/Environment.git",
32 | "version": "0.6.0"
33 | },
34 | {
35 | "package": "HeliumLogger",
36 | "reason": null,
37 | "repositoryURL": "https://github.com/IBM-Swift/HeliumLogger.git",
38 | "version": "1.7.0"
39 | },
40 | {
41 | "package": "KittenCore",
42 | "reason": null,
43 | "repositoryURL": "https://github.com/OpenKitten/KittenCore.git",
44 | "version": "0.2.3"
45 | },
46 | {
47 | "package": "Kitura",
48 | "reason": null,
49 | "repositoryURL": "https://github.com/IBM-Swift/Kitura.git",
50 | "version": "1.7.7"
51 | },
52 | {
53 | "package": "Kitura-TemplateEngine",
54 | "reason": null,
55 | "repositoryURL": "https://github.com/IBM-Swift/Kitura-TemplateEngine.git",
56 | "version": "1.7.1"
57 | },
58 | {
59 | "package": "Kitura-net",
60 | "reason": null,
61 | "repositoryURL": "https://github.com/IBM-Swift/Kitura-net.git",
62 | "version": "1.7.15"
63 | },
64 | {
65 | "package": "LoggerAPI",
66 | "reason": null,
67 | "repositoryURL": "https://github.com/IBM-Swift/LoggerAPI.git",
68 | "version": "1.7.0"
69 | },
70 | {
71 | "package": "MongoKitten",
72 | "reason": null,
73 | "repositoryURL": "https://github.com/PlanTeam/MongoKitten.git",
74 | "version": "4.0.14"
75 | },
76 | {
77 | "package": "SSLService",
78 | "reason": null,
79 | "repositoryURL": "https://github.com/IBM-Swift/BlueSSLService.git",
80 | "version": "0.12.48"
81 | },
82 | {
83 | "package": "Schrodinger",
84 | "reason": null,
85 | "repositoryURL": "https://github.com/OpenKitten/Schrodinger.git",
86 | "version": "1.0.1"
87 | },
88 | {
89 | "package": "Socket",
90 | "reason": null,
91 | "repositoryURL": "https://github.com/IBM-Swift/BlueSocket.git",
92 | "version": "0.12.61"
93 | },
94 | {
95 | "package": "SwiftyJSON",
96 | "reason": null,
97 | "repositoryURL": "https://github.com/IBM-Swift/SwiftyJSON.git",
98 | "version": "16.0.1"
99 | }
100 | ],
101 | "version": 1
102 | }
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(
4 | name: "SwiftServer",
5 | targets: [
6 | Target(name: "SwiftServerLibrary"),
7 | Target(name: "SwiftServer", dependencies: ["SwiftServerLibrary"])
8 | ],
9 | dependencies: [
10 | .Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 1, minor: 7),
11 | .Package(url: "https://github.com/IBM-Swift/HeliumLogger.git", majorVersion: 1, minor: 7),
12 | .Package(url: "https://github.com/PlanTeam/MongoKitten.git", majorVersion: 4, minor: 0),
13 | .Package(url: "https://github.com/Danappelxx/Environment.git", majorVersion: 0, minor: 6)
14 | ])
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Swift Server App
6 | Template to build a server app with Swift and Docker
7 |
8 | [](https://travis-ci.org/choefele/swift-server-app)
9 |
10 | ## Tools
11 | - Xcode
12 | - Download from [Xcode 8](https://developer.apple.com/download/)
13 | - Select Xcode 8 as default `sudo xcode-select -s /Applications/Xcode-beta.app/Contents/Developer/`
14 | - `swiftenv` (optional since Swift built into Xcode 8 is the currently the latest version)
15 | - Install `swiftenv` via [Homebrew](https://swiftenv.fuller.li/en/latest/installation.html#via-homebrew)
16 | - `swiftenv rehash`, `swiftenv install ` (see `.swift-version`)
17 | - Docker
18 | - Install from [Docker website](https://www.docker.com/products/overview)
19 | - Consider installing [Kitematic](https://www.docker.com/products/docker-kitematic) to simplify Docker management
20 |
21 | ## Build & Run with Swift Package Manager
22 | - Run `swift build` in root folder, wait until dependencies have been downloaded and server has been built
23 | - Run dependent services `docker-compose -f docker-compose-dev.yml up`
24 | - Run server `./.build/debug/SwiftServer`
25 | - Test server by executing `curl http://localhost:8090/ping`
26 | - Test DB with `curl -X POST localhost:8090/items`, `curl http://localhost:8090/items`
27 | - Run unit tests with `swift test`
28 |
29 | ## Build & Run with Xcode
30 | - Run `swift package fetch` in root folder to update dependencies
31 | - Generate Xcode project with `swift package generate-xcodeproj`
32 | - Run dependent services `docker-compose -f docker-compose-dev.yml up`
33 | - Open `SwiftServer.xcodeproj` in Xcode and Run `SwiftServer` scheme
34 | - Test server by executing `curl http://localhost:8090/ping`
35 | - Test DB with `curl -X POST localhost:8090/items`, `curl http://localhost:8090/items`
36 | - Run unit tests with CMD-U
37 |
38 | ## Build & Run in Docker
39 | - Build image with `docker-compose -f docker-compose-ci.yml build`; tests a run as part of the build process
40 | - Run with `docker-compose -f docker-compose-ci.yml up [-d]` (stop: `docker-compose down [-v]`, logs: `docker-compose logs -f`)
41 | - Test server by executing `curl http://localhost:8090/ping`
42 | - Test DB with `curl -X POST localhost:8090/items`, `curl http://localhost:8090/items`
43 |
44 | ### Connect `mongo` to database server
45 | - `docker-compose run --rm db mongo mongodb://db` to connect to database
46 | -- `use test`, `db.items.insert({})`, `db.items.find()` to create sample data
47 | - Restart db instance to see that data persists in volume container
48 |
49 | ### Handle managed volumes
50 | - `docker inspect -f "{{json .Mounts}}" swiftserver_db_1` to find out mount point
51 | - `docker volume ls -f dangling=true` to find orphaned managed volumes
52 | - `docker volume rm $(docker volume ls -qf dangling=true)` to remove orphaned volumes
53 |
54 | ### Provision on Digital Ocean
55 | - `docker-machine create --driver digitalocean --digitalocean-access-token SwiftServer`
56 | - `eval "$(docker-machine env SwiftServer)"`, `eval "$(docker-machine env -u)"`
57 | - `docker-machine ssh SwiftServer` to ssh into new machine
58 | - Export/import ssh setup: `https://github.com/bhurlow/machine-share`
59 | - `docker compose -f docker-compose-prod.yml up` to start services
60 |
61 | ## Integration tests
62 | - Install `newman` with `npm install newman --global`
63 | - Run `./run-integration-tests.sh`
64 |
--------------------------------------------------------------------------------
/Sources/SwiftServer/main.swift:
--------------------------------------------------------------------------------
1 | import Kitura
2 | import HeliumLogger
3 | import LoggerAPI
4 | import MongoKitten
5 | import Environment
6 | import SwiftServerLibrary
7 |
8 | HeliumLogger.use()
9 |
10 | for e in Env.all() {
11 | Log.info("\(e.key) = \(e.value)")
12 | }
13 |
14 | let dbUrl = Env["DB_URL"] ?? "mongodb://localhost"
15 | do {
16 | let mongoServer = try Server(dbUrl)
17 | Log.info("Connected to Mongo DB \(dbUrl)")
18 |
19 | let router = Router()
20 |
21 | let itemEndpoint = CRUDMongoEndpoint(collection: mongoServer["test"]["items"],
22 | generateDocument: ItemEndpoint.generateDocument,
23 | generateJsonDictionary: ItemEndpoint.generateJsonDictionary)
24 | let itemHandler = CRUDMongoHandler(endpoint: itemEndpoint)
25 | router.all("/items", handler: itemHandler.handleItems)
26 | router.all("/items/:id", handler: itemHandler.handleItem)
27 |
28 | router.get("/ping") { request, response, next in
29 | response.send("pong")
30 | next()
31 | }
32 |
33 | Kitura.addHTTPServer(onPort: 8090, with: router)
34 | Kitura.run()
35 | } catch {
36 | Log.error("Cannot connect to Mongo DB \(dbUrl)")
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/SwiftServerLibrary/CRUDMongoEndpoint.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CRUDEndpoint.swift
3 | // SwiftServer
4 | //
5 | // Created by Claus Höfele on 25.08.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MongoKitten
11 |
12 | #if os(Linux)
13 | public typealias AnyType = Any
14 | #else
15 | public typealias AnyType = AnyObject
16 | #endif
17 |
18 | public struct CRUDMongoEndpoint {
19 | public init(collection: MongoKitten.Collection, generateDocument: @escaping ([String: String]) -> Document, generateJsonDictionary: @escaping (Document) -> [String: Any]) {
20 | self.collection = collection
21 | self.generateDocument = generateDocument
22 | self.generateJsonDictionary = generateJsonDictionary
23 | }
24 |
25 | public let collection: MongoKitten.Collection
26 | public var generateDocument: ([String: String]) -> Document
27 | public var generateJsonDictionary: (Document) -> [String: Any]
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/SwiftServerLibrary/CRUDMongoHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CRUDHelper.swift
3 | // SwiftServer
4 | //
5 | // Created by Claus Höfele on 21.08.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import Kitura
11 | import SwiftyJSON
12 | import MongoKitten
13 |
14 | // http://www.restapitutorial.com/lessons/httpmethods.html
15 |
16 | public class CRUDMongoHandler {
17 | let mongoProvider: CRUDMongoProvider
18 | let endpoint: CRUDMongoEndpoint
19 |
20 | public init(endpoint: CRUDMongoEndpoint) {
21 | self.mongoProvider = CRUDMongoProvider(collection: endpoint.collection)
22 | self.endpoint = endpoint
23 | }
24 |
25 | public func handleItems(request: RouterRequest, response: RouterResponse, next: () -> Void) throws {
26 | defer {
27 | next()
28 | }
29 |
30 | if request.method == .get {
31 | let documents = try mongoProvider.readItems(query: Query())
32 | let jsonDictionaries = documents.map(endpoint.generateJsonDictionary)
33 | response.send(json: JSON(["items": jsonDictionaries]))
34 | } else if request.method == .post {
35 | guard let document = try mongoProvider.createItem(document: endpoint.generateDocument(request.parameters)) else {
36 | try response.send(status: .internalServerError).end()
37 | return
38 | }
39 |
40 | let jsonDictionary = endpoint.generateJsonDictionary(document)
41 | response.status(.created).send(json: JSON(jsonDictionary))
42 | } else {
43 | try response.send(status: .notImplemented).end()
44 | }
45 | }
46 |
47 | public func handleItem(request: RouterRequest, response: RouterResponse, next: () -> Void) throws {
48 | defer {
49 | next()
50 | }
51 |
52 | if request.method == .get {
53 | guard let id = request.parameters["id"],
54 | let objectId = try? ObjectId(id),
55 | let document = try mongoProvider.readItem(objectId: objectId) else {
56 | try response.send(status: .notFound).end()
57 | return
58 | }
59 |
60 | let jsonDictionary = endpoint.generateJsonDictionary(document)
61 | response.send(json: JSON(jsonDictionary))
62 | } else {
63 | try response.send(status: .notImplemented).end()
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/SwiftServerLibrary/CRUDMongoProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CRUDMongoDatabaseProvider.swift
3 | // SwiftServer
4 | //
5 | // Created by Claus Höfele on 22/08/16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MongoKitten
11 |
12 | public class CRUDMongoProvider {
13 | let collection: MongoKitten.Collection
14 |
15 | init(collection: MongoKitten.Collection) {
16 | self.collection = collection
17 | }
18 |
19 | func createItem(document: Document) throws -> Document? {
20 | let objectId = try collection.insert(document)
21 | return try collection.findOne("_id" == objectId)
22 | }
23 |
24 | func readItems(query: Query) throws -> [Document] {
25 | let documents = try collection.find(query)
26 | return Array(documents)
27 | }
28 |
29 | func readItem(objectId: ObjectId) throws -> Document? {
30 | let document = try collection.findOne("_id" == objectId)
31 | return document
32 | }
33 |
34 | func deleteItem(objectId: ObjectId) throws -> Bool {
35 | let numDocuments = try collection.remove("_id" == objectId, limitedTo: 1)
36 | return numDocuments == 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/SwiftServerLibrary/ItemEndpoint.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Item.swift
3 | // SwiftServer
4 | //
5 | // Created by Claus Höfele on 21.08.16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import MongoKitten
11 |
12 | public struct ItemEndpoint {
13 | public static func generateDocument(parameters: [String: String]) -> Document {
14 | return Document()
15 | }
16 |
17 | public static func generateJsonDictionary(document: Document) -> [String: Any] {
18 | var dictionary = [String: Any]()
19 |
20 | dictionary["id"] = ObjectId(document["_id"])?.hexString
21 | dictionary["name"] = String(document["name"])
22 |
23 | return dictionary
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | #if os(Linux)
2 | import XCTest
3 |
4 | @testable import SwiftServerLibraryTests
5 |
6 | XCTMain([
7 | testCase(ItemTests.allTests)
8 | ])
9 | #endif
--------------------------------------------------------------------------------
/Tests/SwiftServerLibraryTests/ItemTests.swift:
--------------------------------------------------------------------------------
1 | @testable import SwiftServerLibrary
2 | import Kitura
3 | import MongoKitten
4 | import XCTest
5 |
6 | class ItemTests: XCTestCase {
7 | static let allTests = [
8 | ("testGetRequestStatusCode", testGetRequestStatusCode),
9 | ("testGenerateJsonDictionary", testGenerateJsonDictionary)
10 | ]
11 |
12 | func testGetRequestStatusCode() {
13 | let e = expectation(description: "test")
14 | e.fulfill()
15 | waitForExpectations(timeout: 1)
16 |
17 | XCTAssertEqual(40, 40)
18 | }
19 |
20 | func testGenerateJsonDictionary() {
21 | let id = ObjectId()
22 | let name = "name"
23 | var document = Document()
24 | document["_id"] = ObjectId(id)
25 | document["name"] = name
26 |
27 | let jsonDictionary = ItemEndpoint.generateJsonDictionary(document: document)
28 | XCTAssertEqual(jsonDictionary["id"] as? String, id.hexString)
29 | XCTAssertEqual(jsonDictionary["name"] as? String, name)
30 | }
31 |
32 | // func testRouter() {
33 | // guard let mongoServer = try? Server("mongodb://localhost", automatically: false) else { XCTAssert(false); return }
34 | // let router = Router()
35 | //
36 | // let itemEndpoint = CRUDMongoEndpoint(collection: mongoServer["db"]["items"],
37 | // generateDocument: ItemEndpoint.generateDocument,
38 | // generateJsonDictionary: ItemEndpoint.generateJsonDictionary)
39 | // let itemHandler = CRUDMongoHandler(endpoint: itemEndpoint)
40 | // router.all("/items", handler: itemHandler.handleItems)
41 | // router.all("/items/:id", handler: itemHandler.handleItem)
42 | //
43 | //
44 | // let e = expectation(description: "test")
45 | // router.get("/items") { request, response, next in
46 | // response.send("pong")
47 | // next()
48 | // }
49 | // }
50 |
51 | // func testKitura() {
52 | // // Set up router for this test
53 | // let router = Router()
54 | //
55 | // router.get("/zxcv/:p1") { request, _, next in
56 | // let parameter = request.parameters["p1"]
57 | // XCTAssertNotNil(parameter, "URL parameter p1 was nil")
58 | // next()
59 | // }
60 | // router.get("/zxcv/ploni") { request, _, next in
61 | // let parameter = request.parameters["p1"]
62 | // XCTAssertNil(parameter, "URL parameter p1 was not nil, it's value was \(parameter!)")
63 | // next()
64 | // }
65 | // router.all() { _, response, next in
66 | // response.status(.OK).send("OK")
67 | // next()
68 | // }
69 | //
70 | // performServerTest(router) { expectation in
71 | // self.performRequest("get", path: "/zxcv/ploni", callback: { response in
72 | // XCTAssertNotNil(response, "ERROR!!! ClientRequest response object was nil")
73 | // expectation.fulfill()
74 | // })
75 | // }
76 | // }
77 | }
78 |
--------------------------------------------------------------------------------
/docker-compose-ci.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | db:
4 | extends:
5 | file: docker-compose-common.yml
6 | service: db
7 | volumes_from:
8 | - data
9 | data:
10 | extends:
11 | file: docker-compose-common.yml
12 | service: data
13 | app:
14 | extends:
15 | file: docker-compose-common.yml
16 | service: app
17 | build: .
18 | environment:
19 | DB_URL: mongodb://db
20 | links:
21 | - db
22 | volumes:
23 | datavolume:
--------------------------------------------------------------------------------
/docker-compose-common.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | db:
4 | image: mongo:3.2.9
5 | data:
6 | image: alpine:3.4
7 | volumes:
8 | - datavolume:/data/db
9 | command: echo Data container
10 | app:
11 | image: choefele/swift-server-app
12 | ports:
13 | - "8090:8090"
--------------------------------------------------------------------------------
/docker-compose-dev.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | db:
4 | ports:
5 | - "27017:27017"
6 | extends:
7 | file: docker-compose-common.yml
8 | service: db
9 | volumes_from:
10 | - data
11 | data:
12 | extends:
13 | file: docker-compose-common.yml
14 | service: data
15 | volumes:
16 | datavolume:
--------------------------------------------------------------------------------
/docker-compose-prod.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | db:
4 | extends:
5 | file: docker-compose-common.yml
6 | service: db
7 | volumes_from:
8 | - data
9 | data:
10 | extends:
11 | file: docker-compose-common.yml
12 | service: data
13 | app:
14 | extends:
15 | file: docker-compose-common.yml
16 | service: app
17 | environment:
18 | DB_URL: mongodb://db
19 | links:
20 | - db
21 | volumes:
22 | datavolume:
--------------------------------------------------------------------------------
/run-integration-tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | newman run -e Integration\ Tests/SwiftServer%20localhost.postman_environment.json Integration\ Tests/SwiftServer.postman_collection.json
--------------------------------------------------------------------------------
/swift+docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/choefele/swift-server-app/c776e6d60f06d7974507e2da941b1144cfb0ca82/swift+docker.png
--------------------------------------------------------------------------------