Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Serverless APIs in Swift

Rob Allen
November 06, 2017

Serverless APIs in Swift

Serverless systems allow you to concentrate solely on your code and let the provider deal with infrastructure issues such as scaling and routing. Serverless is best known for responding to events, however it is also an excellent choice for APIs and microservices. In this session Rob will share with you how he has used Apache OpenWhisk to implement APIs using the Swift programming language.

You will learn how an API is built in Swift for deployment to Apache OpenWhisk. In order to do this, Rob will also cover key features of the Swift language and why it is good for server-side applications. You'll then learn how to write HTTP APIs frontend by the built-in API Gateway. By walking through this process of building an API, you'll be well placed to build your own serverless APIs.

Rob Allen

November 06, 2017
Tweet

More Decks by Rob Allen

Other Decks in Technology

Transcript

  1. Container deployments 1. Platform (e.g. Kubernetes) 2. Application (e.g. Cloud

    Foundry) 3. Serverless (e.g. OpenWhisk) Rob Allen ~ @akrabat
  2. Serverless? "The first thing to know about serverless computing is

    that "serverless" is a pretty bad name to call it."" Brandon Butler, Network World Rob Allen ~ @akrabat
  3. AKA: Functions as a Service A runtime to execute your

    functions No capacity planning or load balancing Pay for execution, not when idle Rob Allen ~ @akrabat
  4. ThoughtWorks: Technology Radar "Our teams like the serverless approach; it's

    working well for us and we consider it a valid architectural choice." 2017 Technology Radar Rob Allen ~ @akrabat
  5. ThoughtWorks Technology Radar Our teams like the serverless approach; it's

    working well for us and we consider it a valid architectural choice. 2017 Technology Radar Rob Allen ~ @akrabat
  6. Use-cases Synchronous Service is invoked and provides immediate response (HTTP

    requests: APIs, chat bots) Asynchronous Push a message which drives an action later (web hooks, timed events, database changes) Rob Allen ~ @akrabat
  7. Benefits • No need to think about servers • Concentrate

    on application code • Pay only for what you use, when you use it • Language agnostic: NodeJS, Swift, Python, PHP Java, C#, etc Rob Allen ~ @akrabat
  8. Challenges • Start up latency • Time limit • State

    is external • DevOps is still a thing Rob Allen ~ @akrabat
  9. Swift is a general-purpose programming language built using a modern

    approach to safety, performance, and software design patterns. -- swift.org Rob Allen ~ @akrabat
  10. Major features Strong typing Custom operators Type inference Tuples Optionals

    Generics Closures Serialisation ARC Interoperable with C Rob Allen ~ @akrabat
  11. Rock-Paper-Scissors 1 import Foundation 2 3 let shapes = ["rock",

    "paper", "scissors"] 4 5 for count in 1...3 { 6 print(count) 7 sleep(1) 8 } 9 10 srandom(UInt32(Date().timeIntervalSince1970)) 11 let chosenShape = random() % shapes.count 12 print(shapes[chosenShape]); Rob Allen ~ @akrabat
  12. Running your action $ wsk action update ping ping.swift ok:

    updated action ping $ wsk action invoke ping --result { "ack": "2017-11-06 10:15:00" } Rob Allen ~ @akrabat
  13. Web actions $ wsk action update ping ping.swift --web true

    $ curl https://openwhisk.eu-gb.bluemix.net/api/v1/ \ web/19FT_demo/default/ping.json { "ack": "2017-11-06 10:15:00" } Rob Allen ~ @akrabat
  14. API Gateway $ wsk api create /myapp /ping GET ping

    $ curl https://service.eu.apiconnect.ibmcloud.com/gws/apigateway/api/ \ d12f3ba5e86077e6f0c8...830db1e5a05c88edfb12/ping { "ack": "2017-11-06 10:15:00" } Rob Allen ~ @akrabat
  15. HTTP APIs Just because it's serverless doesn't mean we can

    ignore the basics! • Status codes • HTTP method negotiation • Content-type handling • Error handling • Media type format Rob Allen ~ @akrabat
  16. Status codes Send the right one for the right situation!

    1xx Informational 2xx Success 3xx Redirection 4xx Client error 5xx Server error Rob Allen ~ @akrabat
  17. Full control over response Return a dictionary with the keys:

    statusCode, headers, body Do not use an extension on web actions: curl https://openwhisk.eu-gb.bluemix.net/api/v1/ \ web/19FT_demo/default/ping Enable the http response on API Gateway: wsk api create /myapp /ping GET hello --response-type http Rob Allen ~ @akrabat
  18. Full control over response 1 func main(args: [String:Any]) -> [String:Any]

    2 { 3 // our code here does something 4 5 return [ 6 "statusCode" : 201, 7 "headers": [ 8 "Content-Type": "application/json", 9 ], 10 "body" : ["result": "Item created"], 11 ] 12 } Rob Allen ~ @akrabat
  19. HTTP verbs Method Used for Idempotent? GET Retrieve data Yes

    PUT Change data Yes DELETE Delete data Yes POST Change data No PATCH Update data No In Serverless, prefer Idempotent Rob Allen ~ @akrabat
  20. Handling incoming data Parameters arrive in args 1 func main(args:

    [String:Any]) -> [String:Any] { 2 let formatter = DateFormatter() 3 formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" 4 let now = formatter.string(from: Date()) 5 6 var data = ["ack": now] 7 if let state = args["state"] as? String { 8 data["state"] = state 9 } 10 11 return ["body": data] 12 } Rob Allen ~ @akrabat
  21. Handling incoming data GET: $ curl https://openwhisk.eu-gb.bluemix.net/api/.../ping?state=ABC { "ack": "2017-11-06

    10:15:00", "state": "ABC" } POST: $ curl -X POST -d '{"state": "123"}' \ https://openwhisk.eu-gb.bluemix.net/api/.../ping { "ack": "2017-11-06 10:15:00", "state": "123" } Rob Allen ~ @akrabat
  22. HTTP request information 1 func main(args: [String:Any]) -> [String:Any] 2

    { 3 guard 4 let method = args["__ow_method"] as? String, 5 let path = args["__ow_path"] as? String, 6 let headers = args["__ow_headers"] as? [String:Any] 7 else { 8 print("Error. Unable to unwrap HTTP request info.") 9 return ["statusCode": 500, "error": "Internal Server Error"] 10 } 11 12 // `method`, `path` and `headers` are valid Rob Allen ~ @akrabat
  23. Content negotiation Correctly parse the request • Read the Content-Type

    header • Raise "415 Unsupported media type" status if unsupported Create the correct response • Read the Accept header • Set the Content-Type header Rob Allen ~ @akrabat
  24. Reading the HTTP body JSON is parsed automatically, for everything

    else read __ow_body 1 import AEXML; 2 3 func main(args: [String:Any]) -> [String:Any] 4 { 5 let headers = args["__ow_headers"] as? [String:Any] 6 let body = args["__ow_body"] ?? "" 7 let xmlDoc = try AEXMLDocument(xml: body) 8 9 // work with `xmlDoc` 10 } Rob Allen ~ @akrabat