Slide 1

Slide 1 text

ɹ2016/09/27 AKIBA.swift #05 More Server Side? Swift

Slide 2

Slide 2 text

About Me

Slide 3

Slide 3 text

• ాத ޹໌ (Takaaki Tanaka) • Ϋϥεϝιουגࣜձࣾ • iOS ΞϓϦέʔγϣϯΤϯδχΞ • @kongmingtrap • iOS Developer (Swift / Objective-C) • GyazSquare / GitHub

Slide 4

Slide 4 text

ࠓճͷ಺༰͸9/10(౔) HackerTackleʹͯొஃ͖ͯͨ͠ ಺༰Λฤूͨ͠ൃදʹͳΓ·͢

Slide 5

Slide 5 text

[Ϩϙʔτ] HackerTackleʹࢀՃ͖ͯ͠·ͨ͠! #hackt [Ϩϙʔτ] HackerTackleʹొஃ͖ͯ͠·ͨ͠! #hackt

Slide 6

Slide 6 text

Swift is Open Source IUUQTEFWFMPQFSBQQMFDPNTXJGUCMPH JE

Slide 7

Slide 7 text

(PJOH4FSWFSTJEFXJUI4XJGU0QFO4PVSDF IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZ XXED WWDC2016

Slide 8

Slide 8 text

Architecture IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZ XXED

Slide 9

Slide 9 text

Architecture IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZ XXED

Slide 10

Slide 10 text

Agenda • Environment construct • Make • Deploy

Slide 11

Slide 11 text

Environment construct

Slide 12

Slide 12 text

ࠓճͷσϞͰ࠾༻

Slide 13

Slide 13 text

TUBSPWFS

Slide 14

Slide 14 text

Perfect Template IUUQTHJUIVCDPN1FSGFDUMZ4PGU1FSGFDU5FNQMBUFHJU

Slide 15

Slide 15 text

Build 9DPEFPSMBUFS 049&M$BQUBO

Slide 16

Slide 16 text

$ 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

Slide 17

Slide 17 text

$ brew install openssl $ brew link openssl --force Build $ git clone https://github.com/PerfectlySoft/PerfectTemplate.git $ cd PerfectTemplate $ swift build $ .build/debug/PerfectTemplate

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Make

Slide 20

Slide 20 text

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) IUUQTHJUIVCDPN1FSGFDUMZ4PGU1FSGFDU&YBNQMF 63-3PVUJOH

Slide 21

Slide 21 text

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) } }

Slide 22

Slide 22 text

GET Method curl -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}

Slide 23

Slide 23 text

GET Method // check thread let thread = Thread.current print(thread) [INFO] Starting HTTP server on 0.0.0.0:8181 with document root ./webroot {number = 2, name = (null)} {number = 3, name = (null)} {number = 4, name = (null)} શͯͷϦΫΤετ͕ผͷ5ISFBEͰ࣮ߦ͞ Ε͍ͯΔ͜ͱ͕Θ͔Δ

Slide 24

Slide 24 text

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) } }

Slide 25

Slide 25 text

POST Method curl -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"}

Slide 26

Slide 26 text

Database

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

w 1FSGFDU3FEJT w 1FSGFDU42-JUF w 1FSGFDU1PTUHSF42- w 1FSGFDU.Z42- w 1FSGFDU.POHP%# w 1FSGFDU'JMF.BLFS DB Connector

Slide 29

Slide 29 text

w 1FSGFDU3FEJT w 1FSGFDU42-JUF w 1FSGFDU1PTUHSF42- w 1FSGFDU.Z42- w 1FSGFDU.POHP%# w 1FSGFDU'JMF.BLFS DB Connector IUUQTHJUIVCDPN1FSGFDUMZ4PGU1FSGFDU1PTUHSF42-

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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"

Slide 33

Slide 33 text

GET Method … let num = result.numTuples() let messages: [[String : Any]] = (0..

Slide 34

Slide 34 text

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 } …

Slide 35

Slide 35 text

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) …

Slide 36

Slide 36 text

Swift Package Manager

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Full support for Swift 3.0 and Swift Package Manager

Slide 40

Slide 40 text

https://github.com/ikesyo/Himotoki "UZQFTBGF+40/EFDPEJOHMJCSBSZQVSFMZ XSJUUFOJO4XJGU Himotoki

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

struct PostMessage: Decodable { let message: String // MARK: Decodable static func decode(_ e: Extractor) throws -> PostMessage { return try PostMessage( message: e <| "message" ) } } POST Method

Slide 43

Slide 43 text

// 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") let message: PostMessage? = try? PostMessage.decodeValue(json) let result: [String : Any] = 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.message)", "\(createdAt)", "\(updatedAt)"]) result.clear() connection.close() return ["message" : message.message] } ?? [:] try response.setBody(json: result) } catch let error as NSError { print(error) } })

Slide 44

Slide 44 text

struct Message: Decodable { let id: String? let message: String let created_at: String let updated_at: String // MARK: Decodable static func decode(_ e: Extractor) throws -> Message { return try Message( id: e <|? "id", message: e <| "message", created_at: e <| "created_at", updated_at: e <| "updated_at" ) } } struct Messages: Decodable { let messages: [Message] // MARK: Decodable static func decode(_ e: Extractor) throws -> Messages { return try Messages( messages: e <|| ["messages"] ) } } GET Method

Slide 45

Slide 45 text

// get message routes.add(method: .get, uri: "/message", handler: { request, response in defer { response.completed() } do { print(request.params()) 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") let num = result.numTuples() let dict: [[String : Any]] = (0..

Slide 46

Slide 46 text

Deploy

Slide 47

Slide 47 text

IUUQQFSGFDUPSHBXTCVJMEQBDLGPSQFSGFDUBOE TXJGUIUNM AWS Buildpack for Perfect and Swift

Slide 48

Slide 48 text

<4XJGU>4FSWFS4JEF4XJGU1FSGFDUΛ"84ͷ&$ͰՔಇ ͤͯ͞Έ·ͨ͠

Slide 49

Slide 49 text

Recap

Slide 50

Slide 50 text

w ઈࢍൃల్্ w ΫϥΠΞϯταΠυͷ։ൃऀ΋8FC"1*ͷ։ൃΛܦ ݧ͠΍͘͢ͳͬͨ w ίϛολʔʹͳΓ΍͍͢ w 4XJGU1BDLBHF.BOBHFSΛར༻ͯ͠࢖͍׳Εͨϥ ΠϒϥϦΛ૊ΈࠐΉ Recap

Slide 51

Slide 51 text

͋Γ͕ͱ͏͍͟͝·ͨ͠