SlideShare a Scribd company logo
1 of 50
Download to read offline
Networked APIs with Swift
Tim Burks, Google
Use Swift to connect to powerful
cloud services and even create
some of your own.
We'll use a Google Cloud Shell and
a Google API in our examples.
Sign up here:
https://cloud.google.com/free
What is a Networked API?
From the Google Cloud APIs Design Guide:
“Application Programming Interfaces that operate across a network of
computers. They communicate using network protocols including HTTP,
and are frequently produced by different organizations than the ones that
consume them.”
API Styles
1. Remote Procedure Call (RPC)
2. Representational State Transfer (REST)
What is a REST API?
From the Richardson Maturity Model (as described by Martin Fowler):
Level 3 Hypermedia Controls
Level 2 HTTP Verbs
Level 1 Resources
Level 0 HTTP
Hypermedia Controls???
HATEOAS (Hypertext As The Engine Of Application State)
<appointment>
<slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
<link rel = "/linkrels/appointment/cancel" uri = "/slots/1234/appointment"/>
<link rel = "/linkrels/appointment/addTest" uri = "/slots/1234/appointment/tests"/>
<link rel = "self" uri = "/slots/1234/appointment"/>
<link rel = "/linkrels/appointment/changeTime" uri = "/doctors/mjones/slots?date=20100104@status=open"/>
<link rel = "/linkrels/appointment/updateContactInfo" uri = "/patients/jsmith/contactInfo"/>
<link rel = "/linkrels/help" uri = "/help/appointment"/>
</appointment>
(source: Martin Fowler)
REST
Requirements
- Roy Fielding
● A REST API should not be dependent on any single
communication protocol.
● A REST API should not contain any changes to the
communication protocols aside from filling-out or fixing the
details of underspecified bits of standard protocols.
● A REST API should spend almost all of its descriptive effort
in defining the media type(s) used for representing
resources and driving application state, or in defining
extended relation names and/or hypertext-enabled markup
for existing standard media types.
● A REST API must not define fixed resource names or
hierarchies (an obvious coupling of client and server).
● A REST API should never have “typed” resources that are
significant to the client.
● A REST API should be entered with no prior knowledge
beyond the initial URI (bookmark) and set of standardized
media types that are appropriate for the intended audience
(i.e., expected to be understood by any client that might
use the API).
1. HTTP/HTTPS
a. Paths describe resources (nouns)
b. HTTP verbs describe actions
2. JSON Payloads
REST in
Practice
The OpenAPI Specification
The OpenAPI Specification (OAS) defines a
standard, programming language-agnostic
interface description for REST APIs, which allows
both humans and computers to discover and
understand the capabilities of a service without
requiring access to source code, additional
documentation, or inspection of network traffic.
Find OpenAPI descriptions on the web
Generate API support code from OpenAPI.
Make HTTP requests with Swift
1. Prepare a URL.
2. Prepare a request.
3. Perform the request.
1. Prepare a URL
// build URLs with the URLComponents class
var urlComponents = URLComponents(string:urlString)!
// if necessary, add query parameters
var queryItems : [URLQueryItem] = []
for (key, value) in parameters { // [String:String] of parameters
queryItems.append(URLQueryItem(name: key, value: value))
}
urlComponents.queryItems = queryItems
// build the URL
let url = urlComponents.url!
2. Prepare a request
// represent the request with the URLRequest class
var request = URLRequest(url:url)
// add any needed request headers
request.setValue(authorization, forHTTPHeaderField:"Authorization")
// if necessary, set the request method (“GET” is the default)
request.httpMethod = method
3. Perform the request
// use the URLSession class to manage request activity
let session = URLSession(configuration: URLSessionConfiguration.default)
// a URLSessionDataTask handles a specific request
let task: URLSessionDataTask = session.dataTask(with:request)
{(data, response, error) -> Void in
// This block gets called when the request completes.
// NOTE: It will run on a separate thread.
callback(data, response, error)
}
// do something else...
4. Make synchronous calls with URLSessionDataTask and DispatchSemaphore
// Usually we want to handle network calls asynchronously.
// But sometimes (e.g. command-line tools) we want to wait for their results.
// DispatchSemaphore helps us safely communicate between threads
let sem = DispatchSemaphore(value: 0)
let task: URLSessionDataTask = session.dataTask(with:request)
{(data, response, error) -> Void in
callback(data, response, error)
// Use this to signal the end of the task
sem.signal()
}
// This blocks until signal() is called
_ = sem.wait(timeout: DispatchTime.distantFuture)
The Authorization Problem
How do we tell an API server that
it’s ok to respond to our requests?
Authorization
We need to provide a token:
var request = URLRequest(url:url)
request.httpMethod = method
request.httpBody = ...
// add any needed request headers
request.setValue(authorization, forHTTPHeaderField:"Authorization")
How do we get that?
OAuth2 Authorization Flow
For an implementation in Swift, see BrowserTokenProvider.swift
Client Service
Authorization URL
Sign-In Page (HTML)
Human Confirmation
Browser Redirect w/ Code
Token Request (Code)
Token
Web
Browser
Easier ways to get tokens (1 of 2)
If you’re running inside a VM on Google Cloud Platform, you can get a token
from the Google Cloud Metadata Service.
% curl http://metadata/computeMetadata/v1/instance/service-accounts/default/token
{"access_token":"ya29.GqUBUgXcBmIt7vfHsWJT4qVzdhWxwEb2f3tamcA6ykrIsEANZfQnoH0HDCBnlCztLw
cD47w7YENghIucNUIIypLId4C5dXc4H8D93e17MrSbGRe4ipfoQhxPCIhIU3KJsvFjel0HcN2iwf8xURv2z1lWiN
2jkZjzLiMRWPKfSvtBVzuWkIo5uZ5u25IXle3tJ4SICh0-516sU84DFu0wkPO-q1xGpiff","expires_in":179
9,"token_type":"Bearer"}
Then pass “Bearer “ + access_token as the Authorization header.
See GoogleCloudMetadataTokenProvider.swift.
Easier ways to get tokens (2 of 2)
If you’re calling a Google API from anywhere, you can use a Service Account.
1. Create and download the account credentials.
2. Create a JWT token and sign it with the account credentials.
3. POST the signed token to the Google Account Service and get a token!
See ServiceAccountTokenProvider.swift.
Aside: Build an HTTP server with swift-server/http
What about RPC?
It’s just a function call.
service Echo {
// Immediately returns an echo of a request.
rpc Get(EchoRequest) returns (EchoResponse) {}
}
10 billion+
API calls
every second
Protocol Buffers are a language-neutral, platform-neutral, extensible
mechanism for serializing structured data.
“Protocol Buffers” means several things
1. A serialization mechanism
2. An interface description language
3. A methodology
Protocol Buffer Serialization
It’s just a stream of bytes
[field_number<<3 + wire_type] [length if necessary] [data]...
$ hexdump /tmp/request.bin
0000000 0a 05 68 65 6c 6c 6f
0a is “0000 1010”, so
field_number = 1 and wire_type = 2
Protocol Buffers aren’t just for networking
class UserData {
static let sharedInstance = UserData()
public var user : Models_User
init() {
// read info from UserDefaults
if let userdata = UserDefaults.standard.data(forKey:"user") {
do {
user = try Models_User(serializedData:userdata)
} catch {
user = Models_User()
}
} else {
user = Models_User()
}
}
func save() {
DispatchQueue.main.async {
do {
try UserDefaults.standard.set(self.user.serializedData(), forKey:"user")
} catch (let error) {
print("SAVE ERROR (error)")
}
}
}
A Data Definition Language
syntax = "proto3";
package models;
message PlantList {
string id = 1;
string name = 2;
repeated PlantListItem plants = 11;
}
message PlantListItem {
string id = 1;
string botanical_name = 2;
}
message User {
string id = 1;
string name = 2;
repeated PlantList plantLists = 3;
}
A Methodology
% protoc models.proto --swift_out=.
#
# This runs a plugin called protoc-gen-swift
#
# The plugin generates a Swift source file that implements
# the data structures defined in models.proto and code
# for reading and writing them as serialized bytes.
#
Build a Swift client
and service with gRPC
echo.proto
package echo;
service Echo {
// Immediately returns an echo of a request.
rpc Get(EchoRequest) returns (EchoResponse) {}
// Splits a request into words and returns each word in a stream of messages.
rpc Expand(EchoRequest) returns (stream EchoResponse) {}
// Collects a stream of messages and returns them concatenated when the caller closes.
rpc Collect(stream EchoRequest) returns (EchoResponse) {}
// Streams back messages as they are received in an input stream.
rpc Update(stream EchoRequest) returns (stream EchoResponse) {}
}
message EchoRequest {
// The text of a message to be echoed.
string text = 1;
}
message EchoResponse {
// The text of an echo response.
string text = 1;
}
Let’s try it!
https://goo.gl/ux4Txh
https://github.com/grpc/grpc-swift/wiki/
Try-gRPC-Swift-in-a-Google-Compute-Engin
e-VM
EchoService.swift (1/3)
class EchoProvider : Echo_EchoProvider {
// get returns requests as they were received.
func get(request : Echo_EchoRequest, session : Echo_EchoGetSession) throws -> Echo_EchoResponse {
var response = Echo_EchoResponse()
response.text = "Swift echo get: " + request.text
return response
}
// expand splits a request into words and returns each word in a separate message.
func expand(request : Echo_EchoRequest, session : Echo_EchoExpandSession) throws -> Void {
let parts = request.text.components(separatedBy: " ")
var i = 0
for part in parts {
var response = Echo_EchoResponse()
response.text = "Swift echo expand ((i)): (part)"
try session.send(response)
i += 1
sleep(1)
}
}
EchoService.swift (2/3)
// collect collects a sequence of messages and returns them concatenated when the caller closes.
func collect(session : Echo_EchoCollectSession) throws -> Void {
var parts : [String] = []
while true {
do {
let request = try session.receive()
parts.append(request.text)
} catch Echo_EchoServerError.endOfStream {
break
} catch (let error) {
print("(error)")
}
}
var response = Echo_EchoResponse()
response.text = "Swift echo collect: " + parts.joined(separator: " ")
try session.sendAndClose(response)
}
EchoService.swift (3/3)
// update streams back messages as they are received in an input stream.
func update(session : Echo_EchoUpdateSession) throws -> Void {
var count = 0
while true {
do {
let request = try session.receive()
count += 1
var response = Echo_EchoResponse()
response.text = "Swift echo update ((count)): (request.text)"
try session.send(response)
} catch Echo_EchoServerError.endOfStream {
break
} catch (let error) {
print("(error)")
}
}
try session.close()
}
}
main.swift (1/3)
// Unary
if client == "get" {
var requestMessage = Echo_EchoRequest()
requestMessage.text = message
print("Sending: " + requestMessage.text)
let responseMessage = try service.get(requestMessage)
print("get received: " + responseMessage.text)
}
// Server streaming
if client == "expand" {
var requestMessage = Echo_EchoRequest()
requestMessage.text = message
print("Sending: " + requestMessage.text)
let expandCall = try service.expand(requestMessage) {result in }
var running = true
while running {
do {
let responseMessage = try expandCall.receive()
print("Received: (responseMessage.text)")
} catch Echo_EchoClientError.endOfStream {
print("expand closed")
running = false
}
}
}
main.swift (2/3)
// Client streaming
if client == "collect" {
let collectCall = try service.collect() {result in }
let parts = message.components(separatedBy:" ")
for part in parts {
var requestMessage = Echo_EchoRequest()
requestMessage.text = part
print("Sending: " + part)
try collectCall.send(requestMessage) {error in print(error)}
sleep(1)
}
let responseMessage = try collectCall.closeAndReceive()
print("Received: (responseMessage.text)")
}
main.swift (3/3)
// Bidirectional streaming
if client == "update" {
let updateCall = try service.update() {result in}
DispatchQueue.global().async {
var running = true
while running {
do {
let responseMessage = try updateCall.receive()
print("Received: (responseMessage.text)")
} catch Echo_EchoClientError.endOfStream {
print("update closed")
latch.signal()
break
} catch (let error) {
print("error: (error)")
}
}
}
...
...
let parts = message.components(separatedBy:" ")
for part in parts {
var requestMessage = Echo_EchoRequest()
requestMessage.text = part
print("Sending: " + requestMessage.text)
try updateCall.send(requestMessage) {error in print(error)}
sleep(1)
}
try updateCall.closeSend()
// Wait for the call to complete.
latch.wait()
}
}

More Related Content

What's hot

Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...Maarten Balliauw
 
Modern webservices using gRPC and Protocol Buffers in Golang
Modern webservices using gRPC and Protocol Buffers in GolangModern webservices using gRPC and Protocol Buffers in Golang
Modern webservices using gRPC and Protocol Buffers in GolangOmidHojabri1
 
PHP Reactive Programming at Medan Tech Day 2018
PHP Reactive Programming at Medan Tech Day 2018PHP Reactive Programming at Medan Tech Day 2018
PHP Reactive Programming at Medan Tech Day 2018Dolly Aswin Harahap
 
How to reverse engineer Android applications
How to reverse engineer Android applicationsHow to reverse engineer Android applications
How to reverse engineer Android applicationshubx
 
Improving DroidBox
Improving DroidBoxImproving DroidBox
Improving DroidBoxKelwin Yang
 
WEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTH
WEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTHWEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTH
WEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTHBhavsingh Maloth
 
(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine
(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine
(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS EngineZongXian Shen
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLsintelliyole
 
Python Streaming Pipelines with Beam on Flink
Python Streaming Pipelines with Beam on FlinkPython Streaming Pipelines with Beam on Flink
Python Streaming Pipelines with Beam on FlinkAljoscha Krettek
 
Refactoring to Java 8 (Devoxx UK)
Refactoring to Java 8 (Devoxx UK)Refactoring to Java 8 (Devoxx UK)
Refactoring to Java 8 (Devoxx UK)Trisha Gee
 
Eclipse pdt indigo release review
Eclipse pdt   indigo release reviewEclipse pdt   indigo release review
Eclipse pdt indigo release reviewGiang Nguyễn
 
Notes of java first unit
Notes of java first unitNotes of java first unit
Notes of java first unitgowher172236
 
Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...
Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...
Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...Flink Forward
 
1..Net Framework Architecture-(c#)
1..Net Framework Architecture-(c#)1..Net Framework Architecture-(c#)
1..Net Framework Architecture-(c#)Shoaib Ghachi
 
Net serialization
Net serializationNet serialization
Net serializationGreg Sohl
 

What's hot (20)

Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
 
Hack language
Hack languageHack language
Hack language
 
Modern webservices using gRPC and Protocol Buffers in Golang
Modern webservices using gRPC and Protocol Buffers in GolangModern webservices using gRPC and Protocol Buffers in Golang
Modern webservices using gRPC and Protocol Buffers in Golang
 
PHP Reactive Programming at Medan Tech Day 2018
PHP Reactive Programming at Medan Tech Day 2018PHP Reactive Programming at Medan Tech Day 2018
PHP Reactive Programming at Medan Tech Day 2018
 
How to reverse engineer Android applications
How to reverse engineer Android applicationsHow to reverse engineer Android applications
How to reverse engineer Android applications
 
Improving DroidBox
Improving DroidBoxImproving DroidBox
Improving DroidBox
 
WEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTH
WEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTHWEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTH
WEB PROGRAMMING UNIT VIII BY BHAVSINGH MALOTH
 
(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine
(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine
(COSCUP 2015) A Beginner's Journey to Mozilla SpiderMonkey JS Engine
 
Mixing Python and Java
Mixing Python and JavaMixing Python and Java
Mixing Python and Java
 
Unit 8 Java
Unit 8 JavaUnit 8 Java
Unit 8 Java
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLs
 
Python Streaming Pipelines with Beam on Flink
Python Streaming Pipelines with Beam on FlinkPython Streaming Pipelines with Beam on Flink
Python Streaming Pipelines with Beam on Flink
 
Refactoring to Java 8 (Devoxx UK)
Refactoring to Java 8 (Devoxx UK)Refactoring to Java 8 (Devoxx UK)
Refactoring to Java 8 (Devoxx UK)
 
Java Networking
Java NetworkingJava Networking
Java Networking
 
Eclipse pdt indigo release review
Eclipse pdt   indigo release reviewEclipse pdt   indigo release review
Eclipse pdt indigo release review
 
Notes of java first unit
Notes of java first unitNotes of java first unit
Notes of java first unit
 
Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...
Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...
Flink Forward Berlin 2018: Thomas Weise & Aljoscha Krettek - "Python Streamin...
 
1..Net Framework Architecture-(c#)
1..Net Framework Architecture-(c#)1..Net Framework Architecture-(c#)
1..Net Framework Architecture-(c#)
 
Net serialization
Net serializationNet serialization
Net serialization
 
Java Profiling
Java ProfilingJava Profiling
Java Profiling
 

Similar to Networked APIs with swift

CocoaConf: The Language of Mobile Software is APIs
CocoaConf: The Language of Mobile Software is APIsCocoaConf: The Language of Mobile Software is APIs
CocoaConf: The Language of Mobile Software is APIsTim Burks
 
What I learned about APIs in my first year at Google
What I learned about APIs in my first year at GoogleWhat I learned about APIs in my first year at Google
What I learned about APIs in my first year at GoogleTim Burks
 
Xamarin Workshop Noob to Master – Week 5
Xamarin Workshop Noob to Master – Week 5Xamarin Workshop Noob to Master – Week 5
Xamarin Workshop Noob to Master – Week 5Charlin Agramonte
 
Web Server and how we can design app in C#
Web Server and how we can design app  in C#Web Server and how we can design app  in C#
Web Server and how we can design app in C#caohansnnuedu
 
692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded wsmile790243
 
1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will develAgripinaBeaulieuyw
 
Intro to web services
Intro to web servicesIntro to web services
Intro to web servicesNeil Ghosh
 
jkljklj
jkljkljjkljklj
jkljkljhoefo
 
ASP.NET Mvc 4 web api
ASP.NET Mvc 4 web apiASP.NET Mvc 4 web api
ASP.NET Mvc 4 web apiTiago Knoch
 

Similar to Networked APIs with swift (20)

CocoaConf: The Language of Mobile Software is APIs
CocoaConf: The Language of Mobile Software is APIsCocoaConf: The Language of Mobile Software is APIs
CocoaConf: The Language of Mobile Software is APIs
 
What I learned about APIs in my first year at Google
What I learned about APIs in my first year at GoogleWhat I learned about APIs in my first year at Google
What I learned about APIs in my first year at Google
 
Web Service
Web ServiceWeb Service
Web Service
 
Day01 api
Day01   apiDay01   api
Day01 api
 
Xamarin Workshop Noob to Master – Week 5
Xamarin Workshop Noob to Master – Week 5Xamarin Workshop Noob to Master – Week 5
Xamarin Workshop Noob to Master – Week 5
 
Servlet basics
Servlet basicsServlet basics
Servlet basics
 
Web Server and how we can design app in C#
Web Server and how we can design app  in C#Web Server and how we can design app  in C#
Web Server and how we can design app in C#
 
692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w
 
1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce Integration
 
Intro to web services
Intro to web servicesIntro to web services
Intro to web services
 
Switch to Backend 2023
Switch to Backend 2023Switch to Backend 2023
Switch to Backend 2023
 
XML-RPC and SOAP (April 2003)
XML-RPC and SOAP (April 2003)XML-RPC and SOAP (April 2003)
XML-RPC and SOAP (April 2003)
 
jkljklj
jkljkljjkljklj
jkljklj
 
11 asp.net web api
11 asp.net web api11 asp.net web api
11 asp.net web api
 
RESTing with JAX-RS
RESTing with JAX-RSRESTing with JAX-RS
RESTing with JAX-RS
 
Rest with Spring
Rest with SpringRest with Spring
Rest with Spring
 
Rest web service
Rest web serviceRest web service
Rest web service
 
Apitesting.pptx
Apitesting.pptxApitesting.pptx
Apitesting.pptx
 
ASP.NET Mvc 4 web api
ASP.NET Mvc 4 web apiASP.NET Mvc 4 web api
ASP.NET Mvc 4 web api
 

More from Tim Burks

Governing APIs at Scale
Governing APIs at ScaleGoverning APIs at Scale
Governing APIs at ScaleTim Burks
 
Build your next REST API with gRPC
Build your next REST API with gRPCBuild your next REST API with gRPC
Build your next REST API with gRPCTim Burks
 
Taming Cloud APIs with Swift
Taming Cloud APIs with SwiftTaming Cloud APIs with Swift
Taming Cloud APIs with SwiftTim Burks
 
OpenAPI and gRPC Side by-Side
OpenAPI and gRPC Side by-SideOpenAPI and gRPC Side by-Side
OpenAPI and gRPC Side by-SideTim Burks
 
Build Great Networked APIs with Swift, OpenAPI, and gRPC
Build Great Networked APIs with Swift, OpenAPI, and gRPCBuild Great Networked APIs with Swift, OpenAPI, and gRPC
Build Great Networked APIs with Swift, OpenAPI, and gRPCTim Burks
 
Interpreting Objective C
Interpreting Objective CInterpreting Objective C
Interpreting Objective CTim Burks
 
Deep Geek Diving into the iPhone OS and Frameworks
Deep Geek Diving into the iPhone OS and FrameworksDeep Geek Diving into the iPhone OS and Frameworks
Deep Geek Diving into the iPhone OS and FrameworksTim Burks
 
Building Open Radar
Building Open RadarBuilding Open Radar
Building Open RadarTim Burks
 

More from Tim Burks (8)

Governing APIs at Scale
Governing APIs at ScaleGoverning APIs at Scale
Governing APIs at Scale
 
Build your next REST API with gRPC
Build your next REST API with gRPCBuild your next REST API with gRPC
Build your next REST API with gRPC
 
Taming Cloud APIs with Swift
Taming Cloud APIs with SwiftTaming Cloud APIs with Swift
Taming Cloud APIs with Swift
 
OpenAPI and gRPC Side by-Side
OpenAPI and gRPC Side by-SideOpenAPI and gRPC Side by-Side
OpenAPI and gRPC Side by-Side
 
Build Great Networked APIs with Swift, OpenAPI, and gRPC
Build Great Networked APIs with Swift, OpenAPI, and gRPCBuild Great Networked APIs with Swift, OpenAPI, and gRPC
Build Great Networked APIs with Swift, OpenAPI, and gRPC
 
Interpreting Objective C
Interpreting Objective CInterpreting Objective C
Interpreting Objective C
 
Deep Geek Diving into the iPhone OS and Frameworks
Deep Geek Diving into the iPhone OS and FrameworksDeep Geek Diving into the iPhone OS and Frameworks
Deep Geek Diving into the iPhone OS and Frameworks
 
Building Open Radar
Building Open RadarBuilding Open Radar
Building Open Radar
 

Recently uploaded

TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTier1 app
 
OpenChain @ LF Japan Executive Briefing - May 2024
OpenChain @ LF Japan Executive Briefing - May 2024OpenChain @ LF Japan Executive Briefing - May 2024
OpenChain @ LF Japan Executive Briefing - May 2024Shane Coughlan
 
Workforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdfWorkforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdfDeskTrack
 
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAGAI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAGAlluxio, Inc.
 
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdfA Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdfkalichargn70th171
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAlluxio, Inc.
 
how-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfhow-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfMehmet Akar
 
Studiovity film pre-production and screenwriting software
Studiovity film pre-production and screenwriting softwareStudiovity film pre-production and screenwriting software
Studiovity film pre-production and screenwriting softwareinfo611746
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Andrea Goulet
 
INGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by DesignINGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by DesignNeo4j
 
Agnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in KrakówAgnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in Krakówbim.edu.pl
 
A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationHelp Desk Migration
 
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with StrimziStrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzisteffenkarlsson2
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowPeter Caitens
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdfkalichargn70th171
 
IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024vaibhav130304
 
The Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionThe Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionWave PLM
 
iGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by SkilrockiGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by SkilrockSkilrock Technologies
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesKrzysztofKkol1
 
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...Alluxio, Inc.
 

Recently uploaded (20)

TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
OpenChain @ LF Japan Executive Briefing - May 2024
OpenChain @ LF Japan Executive Briefing - May 2024OpenChain @ LF Japan Executive Briefing - May 2024
OpenChain @ LF Japan Executive Briefing - May 2024
 
Workforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdfWorkforce Efficiency with Employee Time Tracking Software.pdf
Workforce Efficiency with Employee Time Tracking Software.pdf
 
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAGAI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
 
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdfA Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning Framework
 
how-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdfhow-to-download-files-safely-from-the-internet.pdf
how-to-download-files-safely-from-the-internet.pdf
 
Studiovity film pre-production and screenwriting software
Studiovity film pre-production and screenwriting softwareStudiovity film pre-production and screenwriting software
Studiovity film pre-production and screenwriting software
 
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
Entropy, Software Quality, and Innovation (presented at Princeton Plasma Phys...
 
INGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by DesignINGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by Design
 
Agnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in KrakówAgnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in Kraków
 
A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data Migration
 
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with StrimziStrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf
 
IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024IT Software Development Resume, Vaibhav jha 2024
IT Software Development Resume, Vaibhav jha 2024
 
The Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion ProductionThe Impact of PLM Software on Fashion Production
The Impact of PLM Software on Fashion Production
 
iGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by SkilrockiGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by Skilrock
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web Services
 
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
 

Networked APIs with swift

  • 1. Networked APIs with Swift Tim Burks, Google
  • 2. Use Swift to connect to powerful cloud services and even create some of your own.
  • 3. We'll use a Google Cloud Shell and a Google API in our examples. Sign up here: https://cloud.google.com/free
  • 4. What is a Networked API? From the Google Cloud APIs Design Guide: “Application Programming Interfaces that operate across a network of computers. They communicate using network protocols including HTTP, and are frequently produced by different organizations than the ones that consume them.”
  • 5. API Styles 1. Remote Procedure Call (RPC) 2. Representational State Transfer (REST)
  • 6. What is a REST API? From the Richardson Maturity Model (as described by Martin Fowler): Level 3 Hypermedia Controls Level 2 HTTP Verbs Level 1 Resources Level 0 HTTP
  • 7. Hypermedia Controls??? HATEOAS (Hypertext As The Engine Of Application State) <appointment> <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/> <patient id = "jsmith"/> <link rel = "/linkrels/appointment/cancel" uri = "/slots/1234/appointment"/> <link rel = "/linkrels/appointment/addTest" uri = "/slots/1234/appointment/tests"/> <link rel = "self" uri = "/slots/1234/appointment"/> <link rel = "/linkrels/appointment/changeTime" uri = "/doctors/mjones/slots?date=20100104@status=open"/> <link rel = "/linkrels/appointment/updateContactInfo" uri = "/patients/jsmith/contactInfo"/> <link rel = "/linkrels/help" uri = "/help/appointment"/> </appointment> (source: Martin Fowler)
  • 8. REST Requirements - Roy Fielding ● A REST API should not be dependent on any single communication protocol. ● A REST API should not contain any changes to the communication protocols aside from filling-out or fixing the details of underspecified bits of standard protocols. ● A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled markup for existing standard media types. ● A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). ● A REST API should never have “typed” resources that are significant to the client. ● A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API).
  • 9. 1. HTTP/HTTPS a. Paths describe resources (nouns) b. HTTP verbs describe actions 2. JSON Payloads REST in Practice
  • 10. The OpenAPI Specification The OpenAPI Specification (OAS) defines a standard, programming language-agnostic interface description for REST APIs, which allows both humans and computers to discover and understand the capabilities of a service without requiring access to source code, additional documentation, or inspection of network traffic.
  • 12. Generate API support code from OpenAPI.
  • 13. Make HTTP requests with Swift 1. Prepare a URL. 2. Prepare a request. 3. Perform the request.
  • 14. 1. Prepare a URL // build URLs with the URLComponents class var urlComponents = URLComponents(string:urlString)! // if necessary, add query parameters var queryItems : [URLQueryItem] = [] for (key, value) in parameters { // [String:String] of parameters queryItems.append(URLQueryItem(name: key, value: value)) } urlComponents.queryItems = queryItems // build the URL let url = urlComponents.url!
  • 15. 2. Prepare a request // represent the request with the URLRequest class var request = URLRequest(url:url) // add any needed request headers request.setValue(authorization, forHTTPHeaderField:"Authorization") // if necessary, set the request method (“GET” is the default) request.httpMethod = method
  • 16. 3. Perform the request // use the URLSession class to manage request activity let session = URLSession(configuration: URLSessionConfiguration.default) // a URLSessionDataTask handles a specific request let task: URLSessionDataTask = session.dataTask(with:request) {(data, response, error) -> Void in // This block gets called when the request completes. // NOTE: It will run on a separate thread. callback(data, response, error) } // do something else...
  • 17. 4. Make synchronous calls with URLSessionDataTask and DispatchSemaphore // Usually we want to handle network calls asynchronously. // But sometimes (e.g. command-line tools) we want to wait for their results. // DispatchSemaphore helps us safely communicate between threads let sem = DispatchSemaphore(value: 0) let task: URLSessionDataTask = session.dataTask(with:request) {(data, response, error) -> Void in callback(data, response, error) // Use this to signal the end of the task sem.signal() } // This blocks until signal() is called _ = sem.wait(timeout: DispatchTime.distantFuture)
  • 18. The Authorization Problem How do we tell an API server that it’s ok to respond to our requests?
  • 19. Authorization We need to provide a token: var request = URLRequest(url:url) request.httpMethod = method request.httpBody = ... // add any needed request headers request.setValue(authorization, forHTTPHeaderField:"Authorization") How do we get that?
  • 20. OAuth2 Authorization Flow For an implementation in Swift, see BrowserTokenProvider.swift Client Service Authorization URL Sign-In Page (HTML) Human Confirmation Browser Redirect w/ Code Token Request (Code) Token Web Browser
  • 21. Easier ways to get tokens (1 of 2) If you’re running inside a VM on Google Cloud Platform, you can get a token from the Google Cloud Metadata Service. % curl http://metadata/computeMetadata/v1/instance/service-accounts/default/token {"access_token":"ya29.GqUBUgXcBmIt7vfHsWJT4qVzdhWxwEb2f3tamcA6ykrIsEANZfQnoH0HDCBnlCztLw cD47w7YENghIucNUIIypLId4C5dXc4H8D93e17MrSbGRe4ipfoQhxPCIhIU3KJsvFjel0HcN2iwf8xURv2z1lWiN 2jkZjzLiMRWPKfSvtBVzuWkIo5uZ5u25IXle3tJ4SICh0-516sU84DFu0wkPO-q1xGpiff","expires_in":179 9,"token_type":"Bearer"} Then pass “Bearer “ + access_token as the Authorization header. See GoogleCloudMetadataTokenProvider.swift.
  • 22. Easier ways to get tokens (2 of 2) If you’re calling a Google API from anywhere, you can use a Service Account. 1. Create and download the account credentials. 2. Create a JWT token and sign it with the account credentials. 3. POST the signed token to the Google Account Service and get a token! See ServiceAccountTokenProvider.swift.
  • 23. Aside: Build an HTTP server with swift-server/http
  • 25. It’s just a function call. service Echo { // Immediately returns an echo of a request. rpc Get(EchoRequest) returns (EchoResponse) {} }
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 33. Protocol Buffers are a language-neutral, platform-neutral, extensible mechanism for serializing structured data.
  • 34. “Protocol Buffers” means several things 1. A serialization mechanism 2. An interface description language 3. A methodology
  • 35. Protocol Buffer Serialization It’s just a stream of bytes [field_number<<3 + wire_type] [length if necessary] [data]... $ hexdump /tmp/request.bin 0000000 0a 05 68 65 6c 6c 6f 0a is “0000 1010”, so field_number = 1 and wire_type = 2
  • 36. Protocol Buffers aren’t just for networking class UserData { static let sharedInstance = UserData() public var user : Models_User init() { // read info from UserDefaults if let userdata = UserDefaults.standard.data(forKey:"user") { do { user = try Models_User(serializedData:userdata) } catch { user = Models_User() } } else { user = Models_User() } } func save() { DispatchQueue.main.async { do { try UserDefaults.standard.set(self.user.serializedData(), forKey:"user") } catch (let error) { print("SAVE ERROR (error)") } } }
  • 37. A Data Definition Language syntax = "proto3"; package models; message PlantList { string id = 1; string name = 2; repeated PlantListItem plants = 11; } message PlantListItem { string id = 1; string botanical_name = 2; } message User { string id = 1; string name = 2; repeated PlantList plantLists = 3; }
  • 38.
  • 39.
  • 40. A Methodology % protoc models.proto --swift_out=. # # This runs a plugin called protoc-gen-swift # # The plugin generates a Swift source file that implements # the data structures defined in models.proto and code # for reading and writing them as serialized bytes. #
  • 41.
  • 42. Build a Swift client and service with gRPC
  • 43. echo.proto package echo; service Echo { // Immediately returns an echo of a request. rpc Get(EchoRequest) returns (EchoResponse) {} // Splits a request into words and returns each word in a stream of messages. rpc Expand(EchoRequest) returns (stream EchoResponse) {} // Collects a stream of messages and returns them concatenated when the caller closes. rpc Collect(stream EchoRequest) returns (EchoResponse) {} // Streams back messages as they are received in an input stream. rpc Update(stream EchoRequest) returns (stream EchoResponse) {} } message EchoRequest { // The text of a message to be echoed. string text = 1; } message EchoResponse { // The text of an echo response. string text = 1; }
  • 45. EchoService.swift (1/3) class EchoProvider : Echo_EchoProvider { // get returns requests as they were received. func get(request : Echo_EchoRequest, session : Echo_EchoGetSession) throws -> Echo_EchoResponse { var response = Echo_EchoResponse() response.text = "Swift echo get: " + request.text return response } // expand splits a request into words and returns each word in a separate message. func expand(request : Echo_EchoRequest, session : Echo_EchoExpandSession) throws -> Void { let parts = request.text.components(separatedBy: " ") var i = 0 for part in parts { var response = Echo_EchoResponse() response.text = "Swift echo expand ((i)): (part)" try session.send(response) i += 1 sleep(1) } }
  • 46. EchoService.swift (2/3) // collect collects a sequence of messages and returns them concatenated when the caller closes. func collect(session : Echo_EchoCollectSession) throws -> Void { var parts : [String] = [] while true { do { let request = try session.receive() parts.append(request.text) } catch Echo_EchoServerError.endOfStream { break } catch (let error) { print("(error)") } } var response = Echo_EchoResponse() response.text = "Swift echo collect: " + parts.joined(separator: " ") try session.sendAndClose(response) }
  • 47. EchoService.swift (3/3) // update streams back messages as they are received in an input stream. func update(session : Echo_EchoUpdateSession) throws -> Void { var count = 0 while true { do { let request = try session.receive() count += 1 var response = Echo_EchoResponse() response.text = "Swift echo update ((count)): (request.text)" try session.send(response) } catch Echo_EchoServerError.endOfStream { break } catch (let error) { print("(error)") } } try session.close() } }
  • 48. main.swift (1/3) // Unary if client == "get" { var requestMessage = Echo_EchoRequest() requestMessage.text = message print("Sending: " + requestMessage.text) let responseMessage = try service.get(requestMessage) print("get received: " + responseMessage.text) } // Server streaming if client == "expand" { var requestMessage = Echo_EchoRequest() requestMessage.text = message print("Sending: " + requestMessage.text) let expandCall = try service.expand(requestMessage) {result in } var running = true while running { do { let responseMessage = try expandCall.receive() print("Received: (responseMessage.text)") } catch Echo_EchoClientError.endOfStream { print("expand closed") running = false } } }
  • 49. main.swift (2/3) // Client streaming if client == "collect" { let collectCall = try service.collect() {result in } let parts = message.components(separatedBy:" ") for part in parts { var requestMessage = Echo_EchoRequest() requestMessage.text = part print("Sending: " + part) try collectCall.send(requestMessage) {error in print(error)} sleep(1) } let responseMessage = try collectCall.closeAndReceive() print("Received: (responseMessage.text)") }
  • 50. main.swift (3/3) // Bidirectional streaming if client == "update" { let updateCall = try service.update() {result in} DispatchQueue.global().async { var running = true while running { do { let responseMessage = try updateCall.receive() print("Received: (responseMessage.text)") } catch Echo_EchoClientError.endOfStream { print("update closed") latch.signal() break } catch (let error) { print("error: (error)") } } } ... ... let parts = message.components(separatedBy:" ") for part in parts { var requestMessage = Echo_EchoRequest() requestMessage.text = part print("Sending: " + requestMessage.text) try updateCall.send(requestMessage) {error in print(error)} sleep(1) } try updateCall.closeSend() // Wait for the call to complete. latch.wait() } }