End-to-end: Building a Web Service in Swift (MCE 2016)

End-to-end: Building a Web Service in Swift (MCE 2016)

Now that Swift is Open Source, Apple has created a new range of
possibilities. You can now take your existing knowledge, code and
apply them to web application development. I'm going to show you
how you can reuse existing skills to build and deploy your first
web service in Swift.

D200a17dd269fd4001bacb11662dab4b?s=128

Kyle Fuller

April 22, 2016
Tweet

Transcript

  1. End-to-end: Building a Web Service in Swift

  2. Who am I?

  3. None
  4. How many of you have build web services or APIs?

  5. What is a web service?

  6. Why Swift on Server?

  7. Swift

  8. Why do many use scripting languages for the web?

  9. None
  10. Code Sharing

  11. Accessible to mobile developers

  12. Performance

  13. Performance Graph Server | Language | request/sec | Comparison ---------|----------|-------------|------------

    Curassow | Swift | 7715.83 | Gunicorn | Python | 5269.49 | 32% less req/s than Curassow Unicorn | Ruby | 4253.33 | 45% less req/s Curassow
  14. None
  15. How

  16. /// Format the given string for presentation func formatForDate(date: NSDate)

    -> String { let formatter = NSDateFormatter() formatter.formatString = "DD MM yyyy" return formatter.stringForDate(date) }
  17. func viewDidLoad() { super.viewDidLoad() // Using our date formatting in

    iOS button.title = formatForDate(NSDate()) }
  18. import Frank get { return formatForDate(NSDate()) }

  19. $ swift build $ .build/debug/date-example

  20. $ curl http://localhost:8000/ 21 04 2016

  21. None
  22. Where to begin

  23. Life-cycle

  24. Planning

  25. https://apiblueprint.org/

  26. # Render [POST /render] + Request (application/json) { "template": "Hello

    {{ name }}", "context": { "name": "Kyle" } }
  27. # Preview [POST /preview] + Response 200 Hello Kyle

  28. Development

  29. Swift Package Manager

  30. Swift 2 vs Swift 3

  31. swiftenv https://swiftenv.fuller.li/

  32. $ swiftenv install 2.2

  33. $ swiftenv local DEVELOPMENT-SNAPSHOT-2016-02-08-a

  34. $ cat .swift-version DEVELOPMENT-SNAPSHOT-2016-02-08-a

  35. $ swift --version Apple Swift version 2.2 $ cd Stencil

    $ swift --version Apple Swift version 3.0-dev
  36. Web Frameworks

  37. Separation of Concerns Web Servers / Web Frameworks

  38. Frank

  39. get("users", "kyle", "followers") { request in }

  40. get("users", *) { (request, username: String) in }

  41. Custom Parameter Type enum Status { case Open case Closed

    }
  42. Custom Parameter Type extension Status : ParameterConvertible { init?(parser: ParameterParser)

    { switch parser.shift() ?? "" { case "open": self = .Open case "closed": self = .Closed default: return nil } } }
  43. get("issues", *) { (request, status: Status) in return "Issues using

    status: \(status)" }
  44. Swift Safety get("/users/:username") { (request, params) in let username =

    params["username"]! return "Hello \(username)" }
  45. None
  46. let router = Router() router.get("/users/:username") { request, response, next in

    let username = request.params["username"] ?? "(nil)" try response.status(HttpStatusCode.OK).send("Hello \(username)") } let server = HttpServer.listen(8090, delegate: router) Server.run()
  47. Web Server

  48. Curassow https://curassow.fuller.li/

  49. $ curassow --workers 5 [INFO] Listening at http://localhost:8080 (65416) [INFO]

    Booting worker process with pid: 65417 [INFO] Booting worker process with pid: 65418 [INFO] Booting worker process with pid: 65419 [INFO] Booting worker process with pid: 65420 [INFO] Booting worker process with pid: 65421
  50. Standards

  51. Learn from others' mistakes

  52. Tight Coupling

  53. Nest https://github.com/nestproject/Nest

  54. func application(request: RequestType) -> ResponseType { return Response(.Ok, body: "Hello

    World") }
  55. Nest Enhancement Proposals

  56. Template Languages

  57. Stencil http://stencil.fuller.li/

  58. There are {{ articles.count }} articles. {% for article in

    articles %} - {{ article.title }} by {{ article.author }}. {% endfor %}
  59. <h1>Users</h1> <ul> {% for user in users %} <li>{{ user

    }}</li> {% endfor %} </ul>
  60. Persistence

  61. ORM Object Relational Mapping

  62. QueryKit http://querykit.org/ let user = User.queryset(context) .filter { $0.name ==

    "Kyle" } .orderBy {} .first
  63. None
  64. Redis (Redbird) let client = try Redbird(config: ...) // Set

    name to MCE try client.command("SET", params: ["name", "MCE"]) // Get the name try client.command("GET", params: ["name"])
  65. PostgreSQL let connection = Connection(host: "localhost", databaseName: "db") try connection.open()

    let usernames = try connection.execute("SELECT username FROM users").map { try $0.data("username") }
  66. Testing

  67. Spectre http://spectre.fuller.li/

  68. describe("a person") { let person = Person(name: "Kyle") $0.it("has a

    name") { try expect(person.name) == "Kyle" } $0.it("returns the name as description") { try expect(person.description) == "Kyle" } }
  69. None
  70. XCTest

  71. class PersonTests: XCTestCase { let person = Person(name: "Kyle") func

    testPersonName() { XCTAssertEqual(person.name, "Kyle") } func testPersonDescription() { XCTAssertEqual(person.description, "Kyle") } }
  72. extension PersonTests: XCTestCaseProvider { var allTests : [(String, () throws

    -> Void)] { return [ ("testPersonName", testPersonName), ("testPersonDescription", testPersonDescription), ] } } XCTMain([ PersonTests(), ])
  73. Dredd https://github.com/apiaryio/dredd

  74. Swift on Travis CI https://swiftenv.fuller.li/en/latest/ integrations/travis-ci.html

  75. Deployment

  76. https://github.com/kylef/heroku-buildpack-swift

  77. $ cat Package.swift import PackageDescription let package = Package( name:

    "Hello", dependencies: [ .Package(url: "https://github.com/nestproject/Frank.git", majorVersion: 0, minor: 3), ] )
  78. $ cat Sources/main.swift import Frank get { _ in return

    "Hello World" } get(*) { (_, username: String) in return "Hello \(username)" }
  79. $ cat .swift-version 2.2-SNAPSHOT-2016-01-11-a

  80. $ swift build $ .build/debug/Hello [INFO] Listening at http://0.0.0.0:8000 (48827)

    [INFO] Booting worker process with pid: 48828
  81. $ cat Procfile web: Hello

  82. $ heroku create --buildpack https://github.com/kylef/heroku-buildpack-swift.git $ git push heroku master

    remote: -----> Swift app detected remote: -----> Installing 2.2-SNAPSHOT-2016-01-11-a remote: -----> Installing clang-3.7.0 remote: -----> Building Package remote: -----> Copying binaries to 'bin'
  83. None
  84. None
  85. Manual Deployment

  86. Monitoring

  87. Logging

  88. print("ERROR: Connection to database failed \(error)")

  89. Papertrail

  90. None
  91. None
  92. What's Next?

  93. Swift 3

  94. Stability

  95. Maturity

  96. What have we covered today • Why you might want

    to build a web application in Swift • How you can design, develop, deploy Swift web applications
  97. kylefuller https://fuller.li/talks