├── .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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
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 |
--------------------------------------------------------------------------------