Server Side? Swift

80
2016/09/10 H-LANE #hackt_h HACKER TACKLE Server Side? Swift

Transcript of Server Side? Swift

Page 1: Server Side? Swift

 2016/09/10 H-LANE #hackt_hHACKER TACKLE

Server Side? Swift

Page 2: Server Side? Swift

About Me

Page 3: Server Side? Swift

• 田中 孝明 (Takaaki Tanaka)

• クラスメソッド株式会社

• iOS アプリケーションエンジニア

• @kongmingtrap • iOS Developer (Swift / Objective-C)

• GyazSquare / GitHub

Page 4: Server Side? Swift

Me and Fukuoka

Page 5: Server Side? Swift

ちょうど1年前まで住んでいました

Page 6: Server Side? Swift

Summary of Swift

Page 7: Server Side? Swift

SwiftSwift is a powerful and intuitive

programming language for macOS, iOS, watchOS and tvOS. Writing Swift code is interactive and fun, the syntax is concise

yet expressive, and Swift includes modern features developers love. Swift

code is safe by design, yet also produces software that runs lightning-fast.

Page 8: Server Side? Swift

History of Swift• 0.x (2014/06)• 1.0 (2014/09)• 1.1 (2014/10)• 1.2 (2015/02)• 2.0 (2015/06)• 2.1 (2015/10)• 2.2 (2016/03)• 3.0 (2016/09)

Page 9: Server Side? Swift

History of Swift• 0.x (2014/06)• 1.0 (2014/09)• 1.1 (2014/10)• 1.2 (2015/02)• 2.0 (2015/06)• 2.1 (2015/10)• 2.2 (2016/03)• 3.0 (2016/09)

黎明期

Page 10: Server Side? Swift

History of Swift• 0.x (2014/06)• 1.0 (2014/09)• 1.1 (2014/10)• 1.2 (2015/02)• 2.0 (2015/06)• 2.1 (2015/10)• 2.2 (2016/03)• 3.0 (2016/09)

成長期

Page 11: Server Side? Swift

History of Swift• 0.x (2014/06)• 1.0 (2014/09)• 1.1 (2014/10)• 1.2 (2015/02)• 2.0 (2015/06)• 2.1 (2015/10)• 2.2 (2016/03)• 3.0 (2016/09)

全盛期

Page 12: Server Side? Swift

[swift-evolution] Looking back on Swift 3 and ahead to Swift 4

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160725/025676.html

ABI安定化など、Swift 3.0で実装予定だった機能が見送られ、Swift 4.0まで持ち越される。。。

Page 13: Server Side? Swift

Swift is Open Source

https://developer.apple.com/swift/blog/?id=34

Page 14: Server Side? Swift

Going Server-side with Swift Open Source

https://developer.apple.com/videos/play/wwdc2016/415/

WWDC2016

Page 15: Server Side? Swift

Architecture

https://developer.apple.com/videos/play/wwdc2016/415/

Page 16: Server Side? Swift

Architecture

https://developer.apple.com/videos/play/wwdc2016/415/

Page 17: Server Side? Swift

Agenda

• Server Side Swift frameworks• Environment construct• Make• Deploy

Page 18: Server Side? Swift

Server Side Swift frameworks

Page 19: Server Side? Swift
Page 20: Server Side? Swift

https://github.com/PerfectlySoft/Perfect

Perfect

Page 21: Server Side? Swift

Perfect• Swift における’Rails’ の立ち位置を目指す • 豊富なDB接続ライブラリ • Mustacheテンプレート • FastCGI + apache2 or Nginx

Page 22: Server Side? Swift

http://qutheory.io/

VAPOR

Page 23: Server Side? Swift

VAPOR

• Laraval like • シンプルに記述できることを目指す • ドキュメントが丁寧にまとめられている

https://github.com/vapor/vapor

Page 24: Server Side? Swift

https://developer.ibm.com/swift/kitura/

KITURA

Page 25: Server Side? Swift

KITURA• IBM製 • IBMのクラウドプラットフォームBluemixがSwiftに対応

• サンドボックスで試すことができる • Swift関連の取り組みも熱心

https://github.com/IBM-Swift

Page 26: Server Side? Swift

http://www.zewo.io/

Zewo

Page 27: Server Side? Swift

Zewo

• 豊富なパッケージ数 • BaseComponentsをVaporと入れ替えることができる

https://github.com/Zewo

Page 28: Server Side? Swift

https://github.com/necolt/Swifton

Swifton

Page 29: Server Side? Swift

https://github.com/necolt/Swifton

Swifton

• Ruby on Rails like

Page 30: Server Side? Swift

https://github.com/noppoMan/Slimane

Slimane

Page 31: Server Side? Swift

https://github.com/noppoMan

Slimane

• expressにインスパイア • マイクロフレームワーク+HTTPサーバー • Yuki Takeiさん作成

Page 32: Server Side? Swift

Environment construct

Page 33: Server Side? Swift

今回のデモで採用

Page 34: Server Side? Swift

8000 star over.

Page 35: Server Side? Swift

Perfect Template

https://github.com/PerfectlySoft/PerfectTemplate.git

Page 36: Server Side? Swift

Build

Xcode 8.0 or later

OS X El Captan (10.11.6)

Page 37: Server Side? Swift

$ swift —version

Apple Swift version 3.0 (swiftlang-800.0.43.6 clang-800.0.38)Target: x86_64-apple-macosx10.9

$ xcode-select --switch /Applications/Xcode.app/Contents/Developer

Build

Page 38: Server Side? Swift

$ brew install openssl$ brew link openssl --force

Build

$ git clone https://github.com/PerfectlySoft/PerfectTemplate.git

$ cd PerfectTemplate$ swift build

$ .build/debug/PerfectTemplate

Page 39: Server Side? Swift
Page 40: Server Side? Swift

// Create HTTP server. let server = HTTPServer()

// Register your own routes and handlers var routes = Routes()

// Add the routes to the server. server.addRoutes(routes)

// Set a listen port of 8181 server.serverPort = 8181

// Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot"

// Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server)

do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }

Server Start

Page 41: Server Side? Swift

// Create HTTP server. let server = HTTPServer()

// Register your own routes and handlers var routes = Routes()

// Add the routes to the server. server.addRoutes(routes)

// Set a listen port of 8181 server.serverPort = 8181

// Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot"

// Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server)

do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }

Server Start

Page 42: Server Side? Swift

// Create HTTP server. let server = HTTPServer()

// Register your own routes and handlers var routes = Routes()

// Add the routes to the server. server.addRoutes(routes)

// Set a listen port of 8181 server.serverPort = 8181

// Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot"

// Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server)

do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }

Server Start

Page 43: Server Side? Swift

// Create HTTP server. let server = HTTPServer()

// Register your own routes and handlers var routes = Routes()

// Add the routes to the server. server.addRoutes(routes)

// Set a listen port of 8181 server.serverPort = 8181

// Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot"

// Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server)

do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }

Server Start

Page 44: Server Side? Swift

// Create HTTP server. let server = HTTPServer()

// Register your own routes and handlers var routes = Routes()

// Add the routes to the server. server.addRoutes(routes)

// Set a listen port of 8181 server.serverPort = 8181

// Set a document root. // This is optional. If you do not want to serve static content then do not set this. // Setting the document root will automatically add a static file handler for the route /** server.documentRoot = "./webroot"

// Gather command line options and further configure the server. // Run the server with --help to see the list of supported arguments. // Command line arguments will supplant any of the values set above. configureServer(server)

do { // Launch the HTTP server. try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }

Server Start

Page 45: Server Side? Swift

Make

Page 46: Server Side? Swift

Router// list routes.add(method: .get, uri: "/list", handler: listHandler) // login routes.add(method: .post, uri: "/login", handler: loginHandler) // get message routes.add(method: .get, uri: "/message", handler: getMessageHandler) // post message routes.add(method: .post, uri: "/message", handler: postMessageHandler)

https://github.com/PerfectlySoft/PerfectExample-URLRouting

Page 47: Server Side? Swift

GET Method// listHandler func listHandler(request: HTTPRequest, _ response: HTTPResponse) { defer { response.completed() } response.setHeader(.contentType, value: "application/json") do { let listArray: [String : Any] = [ "name1": 300, "name2": 230.45, "name3": 150 ] try response.setBody(json: listArray) } catch let error as NSError { print(error) } }

Page 48: Server Side? Swift

GET Methodcurl -v -H "Accept: application/json" -H "Content-type: application/json" -X GET http://0.0.0.0:8181/list* Trying 0.0.0.0...* Connected to 0.0.0.0 (127.0.0.1) port 8181 (#0)> GET /list HTTP/1.1> Host: 0.0.0.0:8181> User-Agent: curl/7.43.0> Accept: application/json> Content-type: application/json> < HTTP/1.1 200 OK< Content-Type: application/json< Connection: Keep-Alive< Content-Length: 40< * Connection #0 to host 0.0.0.0 left intact{"name1":300,"name2":230.45,"name3":150}

Page 49: Server Side? Swift

GET Method// check thread let thread = Thread.current print(thread)

[INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot<NSThread: 0x7fab61c15530>{number = 2, name = (null)}<NSThread: 0x7fab61e06cd0>{number = 3, name = (null)}<NSThread: 0x7fab61f05290>{number = 4, name = (null)}

全てのリクエストが別のThreadで実行されていることがわかる

Page 50: Server Side? Swift

POST Method// loginHandler func loginHandler(request: HTTPRequest, _ response: HTTPResponse) { defer { response.completed() } do { let json = try request.postBodyString?.jsonDecode() response.setHeader(.contentType, value: "application/json") guard let decoded = json as? [String : Any] else { return } let result: [String : Any] = decoded["user"].map { ["result": true, "user": $0] } ?? ["result": false] try response.setBody(json: result) } catch let error as NSError { print(error) } }

Page 51: Server Side? Swift

POST Methodcurl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"user": "tana"}' http://0.0.0.0:8181/login* Trying 0.0.0.0...* Connected to 0.0.0.0 (127.0.0.1) port 8181 (#0)> POST /login HTTP/1.1> Host: 0.0.0.0:8181> User-Agent: curl/7.43.0> Accept: application/json> Content-type: application/json> Content-Length: 16> * upload completely sent off: 16 out of 16 bytes< HTTP/1.1 200 OK< Content-Type: application/json< Connection: Keep-Alive< Content-Length: 29< * Connection #0 to host 0.0.0.0 left intact{"result":true,"user":"tana"}

Page 52: Server Side? Swift

Database

Page 53: Server Side? Swift
Page 54: Server Side? Swift

• Perfect Redis • Perfect SQLite • Perfect PostgreSQL • Perfect MySQL • Perfect MongoDB • Perfect FileMaker

DB Connector

Page 55: Server Side? Swift

• Perfect Redis • Perfect SQLite • Perfect PostgreSQL • Perfect MySQL • Perfect MongoDB • Perfect FileMaker

DB Connector

https://github.com/PerfectlySoft/Perfect-PostgreSQL

Page 56: Server Side? Swift

let package = Package( name: "PerfectTemplate", targets: [], dependencies: [ .Package( url: "https://github.com/PerfectlySoft/Perfect-PostgreSQL.git", versions: Version(0,0,0)..<Version(10,0,0)) ] )

Postgresql

プロジェクト直下のpackage.swiftに Perfect-PostgresSQLを追加する

Page 57: Server Side? Swift

create table message ( id serial primary key, message text, created_at timestamp with time zone, updated_at timestamp with time zone );

• create message table

Create Table

Page 58: Server Side? Swift

GET Method

// get message routes.add(method: .get, uri: "/message", handler: { request, response in defer { response.completed() } do { response.setHeader(.contentType, value: "application/json") let connection = PGConnection() let status = connection.connectdb(db) let result = connection.exec( statement: "select * FROM message order by updated_at desc") …

// DB let db = "postgresql://samplefuku:fukuoka@localhost:5432/exampledb"

Page 59: Server Side? Swift

GET Method… let num = result.numTuples() let messages: [[String : Any]] = (0..<num).map { x in let t1 = result.getFieldString(tupleIndex: x, fieldIndex: 0) let t2 = result.getFieldString(tupleIndex: x, fieldIndex: 1) let t3 = result.getFieldString(tupleIndex: x, fieldIndex: 2) let t4 = result.getFieldString(tupleIndex: x, fieldIndex: 3) let message: [String : Any] = [ "id" : t1, "message" : t2, "created_at" : t3, "updated_at" : t4 ] return message } result.clear() connection.close() try response.setBody(json: ["messages" : messages])

} catch let error as NSError { print(error) } })

Page 60: Server Side? Swift

POST Method// post message routes.add(method: .post, uri: "/message", handler: { request, response in

defer { response.completed() } do { let json = try request.postBodyString?.jsonDecode() response.setHeader(.contentType, value: “application/json")

guard let decoded = json as? [String : Any] else { return } …

Page 61: Server Side? Swift

POST Method… let result: [String : Any] = decoded["message"].map { message in let connection = PGConnection() let status = connection.connectdb(db)

let date = Date() let createdAt = RFC3339DateFormatter.string(from: date) let updatedAt = RFC3339DateFormatter.string(from: date) let result = connection.exec( statement: "insert into message (message, created_at, updated_at) values($1, $2, $3)", params: ["\(message)", "\(createdAt)", "\(updatedAt)"])

result.clear() connection.close() return ["message" : message] } ?? [:] try response.setBody(json: result) …

Page 62: Server Side? Swift

Demo

Page 63: Server Side? Swift

Deploy

Page 64: Server Side? Swift

http://perfect.org/heroku-buildpack-for-perfect-and-swift.html

Heroku Buildpack for Perfect and Swift

Page 65: Server Side? Swift

http://perfect.org/aws-buildpack-for-perfect-and-swift.html

AWS Buildpack for Perfect and Swift

Page 66: Server Side? Swift

AMI

AWSのマネージメントコンソールにログインし、 EC2のAMIから「us-east-1」リージョンにある パブリックイメージから「perfect-ubuntu-1510」を 検索します。

Page 67: Server Side? Swift

AMI

セキュリティグループのインバウンドにHTTPを 追加しておく

Page 68: Server Side? Swift

AMI

$ sudo ssh -i ~/.ssh/xxxxx.pem [email protected]

Page 69: Server Side? Swift

AMI

$ wget https://swift.org/builds/development/ubuntu1510/swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a/swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a-ubuntu15.10.tar.gz$ tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a-ubuntu15.10.tar.gz

https://swift.org/download/#using-downloads

AMIにインストールされているのがSwift 2.2のため、 ビルドするためにサポートされているSwift 3.0の SNAPSHOTを取得する

$ export PATH=./swift-DEVELOPMENT-SNAPSHOT-2016-08-26-a-ubuntu15.10/usr/bin:"${PATH}"

Page 70: Server Side? Swift

Build & Run

$ cd PerfectTemplate$ swift build

$ .build/debug/PerfectTemplate

Page 71: Server Side? Swift

Demo

Page 72: Server Side? Swift

Appendix

Page 73: Server Side? Swift

Call Shell// Commandline func command(launchPath: String, arguments: [String]) -> String { let task = Process() task.launchPath = launchPath task.arguments = arguments let pipe = Pipe() task.standardOutput = pipe task.launch() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String( data: data, encoding: String.Encoding.utf8)! return output }

let cl = command(launchPath: "/bin/echo", arguments: ["aaaa"])

Page 74: Server Side? Swift

Recap

Page 75: Server Side? Swift

• 絶賛発展途上 • クライアントサイドの開発者もWebAPIの開発を経験しやすくなった

• コミッターになりやすい

Recap

Page 76: Server Side? Swift

Happy Swift life!!

Page 77: Server Side? Swift

One more thing...

Page 78: Server Side? Swift

http://dev.classmethod.jp/news/developers-io-2016-in-fukuoka/

Page 79: Server Side? Swift

http://dev.classmethod.jp/news/job-fair-20161007/

Page 80: Server Side? Swift

ありがとうございました🙇