Slide 1

Slide 1 text

Serverless APIs in Swift Rob Allen, Nineteen Feet November 2017 ~ @akrabat

Slide 2

Slide 2 text

I write APIs Rob Allen ~ @akrabat

Slide 3

Slide 3 text

Deployment options 1. Physical servers 2. Virtual machines 3. Containers Rob Allen ~ @akrabat

Slide 4

Slide 4 text

Container deployments 1. Platform (e.g. Kubernetes) 2. Application (e.g. Cloud Foundry) 3. Serverless (e.g. OpenWhisk) Rob Allen ~ @akrabat

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Challenges • Start up latency • Time limit • State is external • DevOps is still a thing Rob Allen ~ @akrabat

Slide 12

Slide 12 text

It's about value Rob Allen ~ @akrabat

Slide 13

Slide 13 text

You are charged by duration of execution & memory used Rob Allen ~ @akrabat

Slide 14

Slide 14 text

Serverless providers Rob Allen ~ @akrabat

Slide 15

Slide 15 text

OpenWhisk Rob Allen ~ @akrabat

Slide 16

Slide 16 text

Open source Multiple providers: IBM Adobe RedHat Rob Allen ~ @akrabat

Slide 17

Slide 17 text

Many runtimes: Swift NodeJS PHP Java Python Docker Rob Allen ~ @akrabat

Slide 18

Slide 18 text

Swift Rob Allen ~ @akrabat

Slide 19

Slide 19 text

Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns. -- swift.org Rob Allen ~ @akrabat

Slide 20

Slide 20 text

Modern Safe Fast Rob Allen ~ @akrabat

Slide 21

Slide 21 text

Major features Strong typing Custom operators Type inference Tuples Optionals Generics Closures Serialisation ARC Interoperable with C Rob Allen ~ @akrabat

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Result $ swift rock-paper-scissors.swift 1 2 3 scissors Rob Allen ~ @akrabat

Slide 24

Slide 24 text

Learn the language Rob Allen ~ @akrabat

Slide 25

Slide 25 text

Remember this? You are charged by duration of execution & memory used Rob Allen ~ @akrabat

Slide 26

Slide 26 text

Performance Rob Allen ~ @akrabat

Slide 27

Slide 27 text

Memory Rob Allen ~ @akrabat

Slide 28

Slide 28 text

Hello world in OpenWhisk Rob Allen ~ @akrabat

Slide 29

Slide 29 text

Hello world in OpenWhisk Rob Allen ~ @akrabat

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Public HTTP access Rob Allen ~ @akrabat

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

What about… API routing? Rate limiting? Authentication? Custom domains? Rob Allen ~ @akrabat

Slide 34

Slide 34 text

API Gateway Rob Allen ~ @akrabat

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Let's talk about HTTP APIs Rob Allen ~ @akrabat

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Summary Rob Allen ~ @akrabat

Slide 48

Slide 48 text

Resources • https://github.com/SwiftOnTheServer/flashcards • https://akrabat.com/talks/serverless-apis-in-swift-mucon/ • https://swift.org • http://openwhisk.incubator.apache.org • https://medium.com/openwhisk Rob Allen ~ @akrabat

Slide 49

Slide 49 text

Thank you! Rob Allen ~ @akrabat