Server Side? Swift

168 views

Published on

HackerTackle 2016/09/10の発表資料です。

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
168
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
7
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Server Side? Swift

  1. 1.  2016/09/10 H-LANE #hackt_h HACKER TACKLE Server Side? Swift
  2. 2. About Me
  3. 3. • 田中 孝明 (Takaaki Tanaka) • クラスメソッド株式会社 • iOS アプリケーションエンジニア • @kongmingtrap • iOS Developer (Swift / Objective-C) • GyazSquare / GitHub
  4. 4. Me and Fukuoka
  5. 5. ちょうど1年前まで住んでいました
  6. 6. Summary of Swift
  7. 7. Swift Swift 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.
  8. 8. 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)
  9. 9. 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) 黎明期
  10. 10. 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) 成長期
  11. 11. 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) 全盛期
  12. 12. [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まで持ち越 される。。。
  13. 13. Swift is Open Source https://developer.apple.com/swift/blog/?id=34
  14. 14. Going Server-side with Swift Open Source https://developer.apple.com/videos/play/ wwdc2016/415/ WWDC2016
  15. 15. Architecture https://developer.apple.com/videos/play/ wwdc2016/415/
  16. 16. Architecture https://developer.apple.com/videos/play/ wwdc2016/415/
  17. 17. Agenda • Server Side Swift frameworks • Environment construct • Make • Deploy
  18. 18. Server Side Swift frameworks
  19. 19. https://github.com/PerfectlySoft/Perfect Perfect
  20. 20. Perfect • Swift における Rails の立ち位置を目指す • 豊富なDB接続ライブラリ • Mustacheテンプレート • FastCGI + apache2 or Nginx
  21. 21. http://qutheory.io/ VAPOR
  22. 22. VAPOR • Laraval like • シンプルに記述できることを目指す • ドキュメントが丁寧にまとめられている https://github.com/vapor/vapor
  23. 23. https://developer.ibm.com/swift/kitura/ KITURA
  24. 24. KITURA • IBM製 • IBMのクラウドプラットフォームBluemixがSwiftに対 応 • サンドボックスで試すことができる • Swift関連の取り組みも熱心 https://github.com/IBM-Swift
  25. 25. http://www.zewo.io/ Zewo
  26. 26. Zewo • 豊富なパッケージ数 • BaseComponentsをVaporと入れ替えることができ る https://github.com/Zewo
  27. 27. https://github.com/necolt/Swifton Swifton
  28. 28. https://github.com/necolt/Swifton Swifton • Ruby on Rails like
  29. 29. https://github.com/noppoMan/Slimane Slimane
  30. 30. https://github.com/noppoMan Slimane • expressにインスパイア • マイクロフレームワーク+HTTPサーバー • Yuki Takeiさん作成
  31. 31. Environment construct
  32. 32. 今回のデモで採用
  33. 33. 8000 star over.
  34. 34. Perfect Template https://github.com/PerfectlySoft/PerfectTemplate.git
  35. 35. Build Xcode 8.0 or later OS X El Captan (10.11.6)
  36. 36. $ 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
  37. 37. $ brew install openssl $ brew link openssl --force Build $ git clone https://github.com/PerfectlySoft/PerfectTemplate.git $ cd PerfectTemplate $ swift build $ .build/debug/PerfectTemplate
  38. 38. // 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
  39. 39. // 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
  40. 40. // 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
  41. 41. // 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
  42. 42. // 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
  43. 43. Make
  44. 44. 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
  45. 45. 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) } }
  46. 46. 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}
  47. 47. 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で実行さ れていることがわかる
  48. 48. 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) } }
  49. 49. 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"}
  50. 50. Database
  51. 51. • Perfect Redis • Perfect SQLite • Perfect PostgreSQL • Perfect MySQL • Perfect MongoDB • Perfect FileMaker DB Connector
  52. 52. • Perfect Redis • Perfect SQLite • Perfect PostgreSQL • Perfect MySQL • Perfect MongoDB • Perfect FileMaker DB Connector https://github.com/PerfectlySoft/Perfect-PostgreSQL
  53. 53. 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を追加する
  54. 54. 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
  55. 55. 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"
  56. 56. 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) } })
  57. 57. 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 } …
  58. 58. 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) …
  59. 59. Demo
  60. 60. Deploy
  61. 61. http://perfect.org/heroku-buildpack-for-perfect-and- swift.html Heroku Buildpack for Perfect and Swift
  62. 62. http://perfect.org/aws-buildpack-for-perfect-and- swift.html AWS Buildpack for Perfect and Swift
  63. 63. AMI AWSのマネージメントコンソールにログインし、 EC2のAMIから「us-east-1」リージョンにある パブリックイメージから「perfect-ubuntu-1510」を 検索します。
  64. 64. AMI セキュリティグループのインバウンドにHTTPを 追加しておく
  65. 65. AMI $ sudo ssh -i ~/.ssh/xxxxx.pem ubuntu@xx.xxx.xx.xxx
  66. 66. 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}"
  67. 67. Build & Run $ cd PerfectTemplate $ swift build $ .build/debug/PerfectTemplate
  68. 68. Demo
  69. 69. Appendix
  70. 70. 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"])
  71. 71. Recap
  72. 72. • 絶賛発展途上 • クライアントサイドの開発者もWebAPI の開発を経験しやすくなった • コミッターになりやすい Recap
  73. 73. Happy Swift life!!
  74. 74. One more thing...
  75. 75. http://dev.classmethod.jp/news/ developers-io-2016-in-fukuoka/
  76. 76. http://dev.classmethod.jp/news/job- fair-20161007/
  77. 77. ありがとうございました🙇

×