├── .gitignore ├── Example-PeopleAPI.postman_collection ├── Package.swift ├── README.md ├── README.zh_CN.md ├── Sources ├── main.swift ├── people.swift └── person.swift └── Tests ├── LinuxMain.swift └── Perfect-JSON-APITests └── Perfect_JSON_APITests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | 65 | Packages/ 66 | *.xcodeproj 67 | buildlinux 68 | Package.resolved 69 | PADockerfile_build 70 | .build_lin 71 | -------------------------------------------------------------------------------- /Example-PeopleAPI.postman_collection: -------------------------------------------------------------------------------- 1 | { 2 | "variables": [], 3 | "info": { 4 | "name": "Example - People API", 5 | "_postman_id": "d63cdf2d-64b6-6ea1-3d96-bc651cbf0c3f", 6 | "description": "", 7 | "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" 8 | }, 9 | "item": [ 10 | { 11 | "name": "http://localhost:8181/ - Hello World", 12 | "request": { 13 | "url": "http://localhost:8181/", 14 | "method": "GET", 15 | "header": [], 16 | "body": { 17 | "mode": "formdata", 18 | "formdata": [] 19 | }, 20 | "description": "" 21 | }, 22 | "response": [] 23 | }, 24 | { 25 | "name": "http://localhost:8181/api/v1/people", 26 | "request": { 27 | "url": "http://localhost:8181/api/v1/people", 28 | "method": "GET", 29 | "header": [], 30 | "body": { 31 | "mode": "formdata", 32 | "formdata": [] 33 | }, 34 | "description": "" 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "http://localhost:8181/api/v1/people", 40 | "request": { 41 | "url": "http://localhost:8181/api/v1/people", 42 | "method": "POST", 43 | "header": [], 44 | "body": { 45 | "mode": "formdata", 46 | "formdata": [ 47 | { 48 | "key": "firstName", 49 | "value": "Arnold", 50 | "type": "text", 51 | "enabled": true 52 | }, 53 | { 54 | "key": "lastName", 55 | "value": "T1000", 56 | "type": "text", 57 | "enabled": true 58 | }, 59 | { 60 | "key": "email", 61 | "value": "t1000@mailinator.com", 62 | "type": "text", 63 | "enabled": true 64 | } 65 | ] 66 | }, 67 | "description": "" 68 | }, 69 | "response": [] 70 | }, 71 | { 72 | "name": "http://localhost:8181/api/v1/people/json", 73 | "request": { 74 | "url": "http://localhost:8181/api/v1/people/json", 75 | "method": "POST", 76 | "header": [ 77 | { 78 | "key": "Content-Type", 79 | "value": "application/json", 80 | "description": "" 81 | } 82 | ], 83 | "body": { 84 | "mode": "raw", 85 | "raw": "{\n \"email\": \"test@example.com\",\n \"firstName\": \"Test\",\n \"lastName\": \"User\"\n}" 86 | }, 87 | "description": "" 88 | }, 89 | "response": [] 90 | } 91 | ] 92 | } -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // Generated automatically by Perfect Assistant Application 2 | // Date: 2017-10-10 14:04:34 +0000 3 | import PackageDescription 4 | let package = Package( 5 | name: "Perfect-JSON-API", 6 | targets: [], 7 | dependencies: [ 8 | .Package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", majorVersion: 3), 9 | ] 10 | ) 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perfect JSON API Example [简体中文](README.zh_CN.md) 2 | 3 |

4 | 5 | Get Involed with Perfect! 6 | 7 |

8 | 9 |

10 | 11 | Star Perfect On Github 12 | 13 | 14 | Stack Overflow 15 | 16 | 17 | Follow Perfect on Twitter 18 | 19 | 20 | Join the Perfect Slack 21 | 22 |

23 | 24 |

25 | 26 | Swift 3.0 27 | 28 | 29 | Platforms OS X | Linux 30 | 31 | 32 | License Apache 33 | 34 | 35 | PerfectlySoft Twitter 36 | 37 | 38 | Slack Status 39 | 40 |

41 | 42 | An Example JSON API for Perfect 43 | 44 | This package builds with Swift Package Manager and is part of the [Perfect](https://github.com/PerfectlySoft/Perfect) project. 45 | 46 | Ensure you have installed Xcode 8.0 or later. 47 | 48 | ## Setup - Xcode 8 49 | 50 | * Check out or download the project; 51 | * In terminal, navigate to the directory and execute 52 | 53 | ``` 54 | swift package generate-xcodeproj 55 | ``` 56 | 57 | * Open `Perfect-JSON-API.xcodeproj` 58 | * Add to the "Library Search Paths" in "Project Settings" `$(PROJECT_DIR)`, recursive. **(This step will be unneeded in a future release of Xcode 8.)** 59 | * Select the Executable build target from the build targets dropdown in Xcode 60 | * Run (cmd-R) to build & run in Xcode. 61 | 62 | In Xcode's console output pane you will see: 63 | 64 | ``` 65 | [INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot 66 | ``` 67 | 68 | * In a browser, visit [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people) 69 | 70 | ## Setup - Terminal 71 | 72 | * Check out or download the project; 73 | * In terminal, navigate to the directory 74 | * Execute `swift build` 75 | * Once the project has compiled, execute `./.build/debug/Perfect-JSON-API` 76 | 77 | The output you will see: 78 | 79 | ``` 80 | [INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot 81 | ``` 82 | 83 | * In a browser, visit [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people) 84 | 85 | ## Included Routes 86 | 87 | The following routes are included in this API for demonstration purposes: 88 | 89 | * GET: [http://localhost:8181/](http://localhost:8181/) - A demonstration HTML "Hello, world!" page is returned. 90 | * GET: [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people) - Returns a JSON list of persons from the included mock data. 91 | * POST: [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people) - Adds a person to the internal mock object and returns the new array as JSON. Note the following POST params are expected: `firstName`, `lastName`, `email`. 92 | * POST: [http://localhost:8181/api/v1/people/json](http://localhost:8181/api/v1/people/json) - Accepts a raw body of JSON. Adds a new person, returns the new list. JSON would be in the following format: 93 | 94 | ``` javascript 95 | { 96 | "email": "test@example.com", 97 | "firstName": "Test", 98 | "lastName": "User" 99 | } 100 | ``` 101 | 102 | ## Postman Collection 103 | 104 | The repo includes a file `Example-PeopleAPI.postman_collection` which is a Postman URL collection. 105 | 106 | With Postman installed, import and use to easily query the routes. 107 | 108 | ## Issues 109 | 110 | We are transitioning to using JIRA for all bugs and support related issues, therefore the GitHub issues has been disabled. 111 | 112 | If you find a mistake, bug, or any other helpful suggestion you'd like to make on the docs please head over to [http://jira.perfect.org:8080/servicedesk/customer/portal/1](http://jira.perfect.org:8080/servicedesk/customer/portal/1) and raise it. 113 | 114 | A comprehensive list of open issues can be found at [http://jira.perfect.org:8080/projects/ISS/issues](http://jira.perfect.org:8080/projects/ISS/issues) 115 | 116 | 117 | ## Further Information 118 | For more information on the Perfect project, please visit [perfect.org](http://perfect.org). 119 | -------------------------------------------------------------------------------- /README.zh_CN.md: -------------------------------------------------------------------------------- 1 | # Perfect JSON API 示例 [English](README.md) 2 | 3 |

4 | 5 | Get Involed with Perfect! 6 | 7 |

8 | 9 |

10 | 11 | Star Perfect On Github 12 | 13 | 14 | Stack Overflow 15 | 16 | 17 | Follow Perfect on Twitter 18 | 19 | 20 | Join the Perfect Slack 21 | 22 |

23 | 24 |

25 | 26 | Swift 3.0 27 | 28 | 29 | Platforms OS X | Linux 30 | 31 | 32 | License Apache 33 | 34 | 35 | PerfectlySoft Twitter 36 | 37 | 38 | Slack Status 39 | 40 |

41 | 42 | 一个Perfect JSON API示例 43 | 44 | 该项目通过SPM软件包管理器编译,是[Perfect](https://github.com/PerfectlySoft/Perfect)项目之一
45 | 请确保您已经安装了Xcode 8.0或更高版本。 46 | 47 | ## 准备工作 - 使用Xcode 8 48 | 49 | * 导出或下载工程 50 | * 在终端中,导航到目录并执行 51 | 52 | ``` 53 | swift package generate-xcodeproj 54 | ``` 55 | 56 | * 打开 `Perfect-JSON-API.xcodeproj` 57 | * 在"Project Settings"下的"Library Search Paths"中添加`$(PROJECT_DIR)`递归. **(这一步将不需要在更高版本的Xcode 8中做)** 58 | * 在Xcode的构建目标下拉来选择可执行文件 59 | * 在Xcode中使用(cmd-R)命令来编译运行项目工程 60 | 61 | 您将会在Xcode控制台看到如下输出: 62 | 63 | ``` 64 | [INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot 65 | ``` 66 | 67 | * 打开浏览器,通过 [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people)访问 68 | 69 | ## 准备工作 - 使用终端 70 | 71 | * 导出或下载工程; 72 | * 在终端中,导航到工程目录 73 | * 执行 `swift build` 74 | * 项目编译成功后, 请执行 `./.build/debug/Perfect-JSON-API` 75 | 76 | 您将会看到如下输出: 77 | 78 | ``` 79 | [INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot 80 | ``` 81 | 82 | * 打开浏览器,通过 [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people)访问 83 | 84 | ## 已包含的路由 85 | 86 | 此API中包含下列演示路由: 87 | 88 | * GET: [http://localhost:8181/](http://localhost:8181/) - 一个返回显示"Hello, world!"的HTML页面。 89 | * GET: [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people) - 从模拟数据返回JSON形式的persons列表。 90 | * POST: [http://localhost:8181/api/v1/people](http://localhost:8181/api/v1/people) - 将一个person添加到内部模拟对象并返回一个JSON形式的数组. 请注意需要下列参数: `firstName`, `lastName`, `email`. 91 | * POST: [http://localhost:8181/api/v1/people/json](http://localhost:8181/api/v1/people/json) - 接受原本的JSON, 添加一个新的person, 返回一个新的列表. JSON是下面的格式: 92 | 93 | ``` javascript 94 | { 95 | "email": "test@example.com", 96 | "firstName": "Test", 97 | "lastName": "User" 98 | } 99 | ``` 100 | ## Postman Collection 101 | 102 | 文件夹包含了一个Postman的URL集合的`Example-WeatherAPI.postman_collection`文件 103 | 104 | 如果已经安装了Postman,就可以导入文件并轻松使用请求路由 105 | 106 | ## 问题报告 107 | 108 | 目前我们已经把所有错误报告合并转移到了JIRA上,因此github原有的错误汇报功能不能用于本项目。 109 | 110 | 您的任何宝贵建意见或建议,或者发现我们的程序有问题,欢迎您在这里告诉我们。[http://jira.perfect.org:8080/servicedesk/customer/portal/1](http://jira.perfect.org:8080/servicedesk/customer/portal/1)。 111 | 112 | 目前问题清单请参考以下链接: [http://jira.perfect.org:8080/projects/ISS/issues](http://jira.perfect.org:8080/projects/ISS/issues) 113 | 114 | 115 | 116 | ## 更多内容 117 | 关于Perfect更多内容,请参考[perfect.org](http://perfect.org)官网。 118 | -------------------------------------------------------------------------------- /Sources/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // Perfect JSON API Example 4 | // 5 | // Created by Jonathan Guthrie on 2016-09-26. 6 | // Copyright (C) 2015 PerfectlySoft, Inc. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This source file is part of the Perfect.org open source project 11 | // 12 | // Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors 13 | // Licensed under Apache License v2.0 14 | // 15 | // See http://perfect.org/licensing.html for license information 16 | // 17 | //===----------------------------------------------------------------------===// 18 | // 19 | 20 | import PerfectLib 21 | import PerfectHTTP 22 | import PerfectHTTPServer 23 | 24 | // Create HTTP server. 25 | let server = HTTPServer() 26 | 27 | // Create the container variable for routes to be added to. 28 | var routes = Routes() 29 | 30 | // Register your own routes and handlers 31 | // This is an example "Hello, world!" HTML route 32 | routes.add(method: .get, uri: "/", handler: { 33 | request, response in 34 | // Setting the response content type explicitly to text/html 35 | response.setHeader(.contentType, value: "text/html") 36 | // Adding some HTML to the response body object 37 | response.appendBody(string: "Hello, world!Hello, world!") 38 | // Signalling that the request is completed 39 | response.completed() 40 | } 41 | ) 42 | 43 | 44 | // Adding a route to handle the GET people list URL 45 | routes.add(method: .get, uri: "/api/v1/people", handler: { 46 | request, response in 47 | 48 | let people = People() 49 | 50 | // Setting the response content type explicitly to application/json 51 | response.setHeader(.contentType, value: "application/json") 52 | // Setting the body response to the JSON list generated 53 | response.appendBody(string: people.list()) 54 | // Signalling that the request is completed 55 | response.completed() 56 | } 57 | ) 58 | 59 | // Adding a route to handle the POST people add URL, with post body params 60 | routes.add(method: .post, uri: "/api/v1/people", handler: { 61 | request, response in 62 | 63 | let people = People() 64 | 65 | // Setting the response content type explicitly to application/json 66 | response.setHeader(.contentType, value: "application/json") 67 | // Adding a new "person", passing the complete HTTPRequest object to the function. 68 | response.appendBody(string: people.add(request)) 69 | // Signalling that the request is completed 70 | response.completed() 71 | } 72 | ) 73 | 74 | // Adding a route to handle the POST people add via JSON 75 | routes.add(method: .post, uri: "/api/v1/people/json", handler: { 76 | request, response in 77 | 78 | let people = People() 79 | 80 | // Setting the response content type explicitly to application/json 81 | response.setHeader(.contentType, value: "application/json") 82 | // Adding a new "person", passing the just the request's post body as a raw string to the function. 83 | response.appendBody(string: people.add(request.postBodyString!)) 84 | // Signalling that the request is completed 85 | response.completed() 86 | } 87 | ) 88 | 89 | 90 | 91 | // Add the routes to the server. 92 | server.addRoutes(routes) 93 | 94 | // Set a listen port of 8181 95 | server.serverPort = 8181 96 | 97 | do { 98 | // Launch the HTTP server. 99 | try server.start() 100 | } catch PerfectError.networkError(let err, let msg) { 101 | print("Network error thrown: \(err) \(msg)") 102 | } 103 | -------------------------------------------------------------------------------- /Sources/people.swift: -------------------------------------------------------------------------------- 1 | // 2 | // people.swift 3 | // Perfect-JSON-API 4 | // 5 | // Created by Jonathan Guthrie on 2016-09-26. 6 | // 7 | // 8 | 9 | import PerfectHTTP 10 | 11 | public class People { 12 | // Container for array of type Person 13 | var data = [Person]() 14 | 15 | // Populating with a mock data object 16 | init(){ 17 | data = [ 18 | Person(firstName: "Sarah", lastName: "Conner", email: "sarah.conner@mailinator.com"), 19 | Person(firstName: "John", lastName: "Conner", email: "jane.smith@mailinator.com"), 20 | Person(firstName: "Kyle", lastName: "Reese", email: "kyle.reese@mailinator.com"), 21 | Person(firstName: "Marcus", lastName: "Wright", email: "marcus.wright@mailinator.com") 22 | ] 23 | } 24 | 25 | // A simple JSON encoding function for listing data members. 26 | // Ordinarily in an API list directive, cursor commands would be included. 27 | public func list() -> String { 28 | return toString() 29 | } 30 | 31 | // Accepts the HTTPRequest object and adds a new Person from post params. 32 | public func add(_ request: HTTPRequest) -> String { 33 | let new = Person( 34 | firstName: request.param(name: "firstName") ?? "", 35 | lastName: request.param(name: "lastName") ?? "", 36 | email: request.param(name: "email") ?? "" 37 | ) 38 | data.append(new) 39 | return toString() 40 | } 41 | 42 | // Accepts raw JSON string, to be converted to JSON and consumed. 43 | public func add(_ json: String) -> String { 44 | do { 45 | let incoming = try json.jsonDecode() as! [String: String] 46 | let new = Person( 47 | firstName: incoming["firstName"] ?? "", 48 | lastName: incoming["lastName"] ?? "", 49 | email: incoming["email"] ?? "" 50 | ) 51 | data.append(new) 52 | } catch { 53 | return "ERROR" 54 | } 55 | return toString() 56 | } 57 | 58 | 59 | // Convenient encoding method that returns a string from JSON objects. 60 | private func toString() -> String { 61 | var out = [String]() 62 | 63 | for m in self.data { 64 | do { 65 | out.append(try m.jsonEncodedString()) 66 | } catch { 67 | print(error) 68 | } 69 | } 70 | return "[\(out.joined(separator: ","))]" 71 | } 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /Sources/person.swift: -------------------------------------------------------------------------------- 1 | // 2 | // person.swift 3 | // Perfect-JSON-API 4 | // 5 | // Created by Jonathan Guthrie on 2016-09-26. 6 | // 7 | // 8 | import PerfectLib 9 | 10 | class Person : JSONConvertibleObject { 11 | 12 | static let registerName = "person" 13 | 14 | var firstName: String = "" 15 | var lastName: String = "" 16 | var email: String = "" 17 | 18 | var fullName: String { 19 | return "\(firstName) \(lastName)" 20 | } 21 | 22 | init(firstName: String, lastName: String, email: String) { 23 | self.firstName = firstName 24 | self.lastName = lastName 25 | self.email = email 26 | } 27 | 28 | override public func setJSONValues(_ values: [String : Any]) { 29 | self.firstName = getJSONValue(named: "firstName", from: values, defaultValue: "") 30 | self.lastName = getJSONValue(named: "lastName", from: values, defaultValue: "") 31 | self.email = getJSONValue(named: "email", from: values, defaultValue: "") 32 | } 33 | override public func getJSONValues() -> [String : Any] { 34 | return [ 35 | "firstName":firstName, 36 | "lastName":lastName, 37 | "email":email 38 | ] 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Perfect_JSON_APITests 3 | 4 | XCTMain([ 5 | testCase(Perfect_JSON_APITests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Tests/Perfect-JSON-APITests/Perfect_JSON_APITests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Perfect_JSON_API 3 | 4 | class Perfect_JSON_APITests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct results. 8 | XCTAssertEqual(Perfect_JSON_API().text, "Hello, World!") 9 | } 10 | 11 | 12 | static var allTests : [(String, (Perfect_JSON_APITests) -> () throws -> Void)] { 13 | return [ 14 | ("testExample", testExample), 15 | ] 16 | } 17 | } 18 | --------------------------------------------------------------------------------