SlideShare a Scribd company logo
Creating Great
REST and gRPC
API Experiences
(in Swift)
Tim Burks
Google
October 4, 2000
CL 23852 by jeff
ProtocolBuffer, a class for encoding hierarchical data in
a compact binary form...
Co-designed and Rev. by Sanjay
Creating Great REST and gRPC API Experiences (in Swift)
Creating Great REST and gRPC API Experiences (in Swift)
Creating Great REST and gRPC API Experiences (in Swift)
Creating Great REST and gRPC API Experiences (in Swift)
Creating Great REST and gRPC API Experiences (in Swift)
Creating Great REST and gRPC API Experiences (in Swift)
Creating Great REST and gRPC API Experiences (in Swift)
10 billion+
API calls
every second
Protocol Buffers
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
A Serialization Mechanism
An encoded message is 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
An Interface Definition Language
syntax = "proto3";
package echo;
// The message used for echo requests and responses.
message EchoMessage {
string text = 1;
}
A Methodology
% protoc echo.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.
echo.pb.swift
// DO NOT EDIT.
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: echo.proto
//
// For information on using the generated types, please see the documenation:
// https://github.com/apple/swift-protobuf/
...
/// The message used for echo requests and responses.
struct Echo_EchoMessage {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var text: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
A Data Definition Language
syntax = "proto3";
package models;
message User {
string id = 1;
string name = 2;
repeated PlantList plantLists = 3;
}
message PlantList {
string id = 1;
string name = 2;
repeated PlantListItem plants = 11;
}
message PlantListItem {
string id = 1;
string botanical_name = 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)")
}
}
}
Interface Builder for Data
message Person {
string name = 1;
int32 id = 2;
string email = 3;
message PhoneNumber {
string number = 1;
}
repeated PhoneNumber phone = 4;
}
Interface Builder: Developers specify
their interfaces using a special tool,
tooling compiles and integrates that into
their apps.
Protocol Buffers: Developers specify
their data structures using a special
language, tooling compiles and
integrates that into their apps.
Let’s talk about Networked APIs
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)
An RPC is just a function call.
service Echo {
// Immediately returns an echo of a request.
rpc Get(EchoRequest) returns (EchoResponse) {}
}
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
OpenAPI
Industry standard format for describing for REST APIs
Originally designed for documentation, now with many other applications: API
Authoring, Validation, Documentation, Analysis, Search, Testing, Mocking,
Management, Code Generation
2010-11: Google API Discovery Format
Discovery Format Code Generators
github.com/google/google-api-go-client
github.com/google/google-api-python-client
github.com/google/google-api-swift-client
github.com/google/google-auth-library-swift
Authorization: How do we tell an API server
that it’s ok to respond to our requests?
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 and sign it with the account credentials.
3. POST the signed JWT to the Google Account Service and get a token!
See ServiceAccountTokenProvider.swift.
Aside: Build an HTTP server with swift-server/http
● REST APIs
○ Discovery Format
○ 250+API descriptions
○ 10+ generators
● gRPC APIs
○ Protocol Buffer Language
○ 40+ gRPC-based APIs
○ 7+ target languages
gRPC
Open-Source messaging system based on Google’s internal API architecture.
Used for code and documentation generation, API management, and support
services for APIs and microservices running at very large scale.
gRPC is owned by the Cloud Native Computing Foundation
gRPC Adoption
Microservices: in data centres
Streaming telemetry from network devices
Client Server communication/Internal APIs
Mobile Apps
gRPC
Transport Mechanism
Client → Server
Server → Client
Initial
Metadata
MsgMsg
End of
Stream
Status & Trailing
Metadata
Initial
Metadata
MsgMsg Msg
HTTP/2
Creating Great REST and gRPC API Experiences (in Swift)
Cross-Language Interoperability
Java
Service
Python
Service
GoLang
Service
C++
Service
gRPC
Service
gRPC
Stub
gRPC
Stub
gRPC
Stub
gRPC
Stub
gRPC
Service
gRPC
Service
gRPC
Service
gRPC
Stub
Creating Great REST and gRPC API Experiences (in Swift)
Build a Swift client
and service with
gRPC
https://github.com/grpc/gr
pc-swift/wiki/Try-gRPC-Swi
ft-in-a-Google-Compute-Eng
ine-VM
or just
https://goo.gl/ux4Txh
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;
}
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()
}
}
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()
}
}
Why generate client libraries for APIs?
Make it easier to use Google APIs.
● Hide implementation details from API consumers.
● Develop API clients faster.
● Improve API client quality.
○ Better performance
○ Better consistency
○ Fewer bugs
Generated API Clients
a.k.a.
“GAPICs”
GAPIC Customers
Google Cloud APIs
Google Ads APIs
…other Google teams
…external API producers?
GAPIC Features and Benefits
● Usability:
○ Trivial getting-started experience
○ Flattening
○ Natural paging
○ Long-running operations
○ Sample code for every method
○ Resource name types (e.g. for /projects/{project}/topics/{topic})
● Performance:
○ Batching
● Reliability:
○ Automatic retries
Trivial Getting-Started Experience
GAPIC client:
Channel channel =
NettyChannelBuilder.forAddress(API_ENTRY, API_PORT).build();
List<ClientInterceptor> interceptors = new ArrayList<>();
GoogleCredentials credentials =
GoogleCredentials.getApplicationDefault();
interceptors.add(
ChannelFactory.credentialInterceptor(credentials));
LoggingService stub =
LoggingServiceGrpc.newBlockingStub(channel, interceptors);
gRPC:
LoggingClient client = LoggingClient.create();
Automatic Retry and Flattening
GAPIC client:
LoggingService stub = ...;
// Note: this only does a simple retry, exponential backoff
// is more complex
DeleteLogRequest request = DeleteLogRequest.newBuilder()
.setLogName(LOG_NAME)
.build();
for (int i = 0; i < MAX_RETRY; i++) {
try {
stub.deleteLog(request);
} catch (RpcException e) {
if (i == MAX_RETRY) throw e;
}
}
gRPC:
LoggingClient client = LoggingClient.create();
client.deleteLog(LOG_NAME);
Natural Pagination
GAPIC client:
LoggingService stub = ...;
ListLogsRequest request = ListLogsRequest.newBuilder()
.setParentName("projects/" + PROJECT_ID)
.build();
while (true) {
ListLogsResponse response = stub.listLogs(request);
for (Log log : response.getLogsList()) {
System.out.printf("Log: %s%n", log.getDisplayName());
}
String nextPageToken = response.getNextPageToken();
if (nextPageToken != null) {
request = ListLogsRequest.newBuilder()
.setPageToken(nextPageToken).build();
} else {
break;
}
}
gRPC:
LoggingClient client = LoggingClient.create();
ParentNameOneOf parent =
ParentNameOneOf.from(ProjectName.create(PROJECT_ID));
for (Log log : client.listLogs(PARENT).iterateAll()) {
System.out.printf("Log: %s%n", log.getDisplayName());
}
Long-Running Operations
SpeechClient speechClient = SpeechClient.create();
OperationFuture<LongRunningRecognizeResponse> recognizeOperation =
speechClient.longRunningRecognizeAsync(config, audio);
…
LongRunningRecognizeResponse response = recognizeOperation.get();
● Java: OperationFuture
○ Polls the service until the LRO is done
○ Provides metadata as the LRO is in progress
○ Provides the final result
Resource Name Types
GAPIC client:
PublisherService stub = ...;
CreateTopicRequest request = CreateTopicRequest.newBuilder()
.setTopic("projects/my-project/topics/my-topic")
.build();
Topic response = stub.createTopic(request);
gRPC:
TopicAdminClient topicAdminClient = TopicAdminClient.create();
TopicName name = TopicName.create("my-project", "my-topic");
Topic response = topicAdminClient.createTopic(name);
Generated Sample Code
GAPIC Project Architecture (hosted at github.com/googleapis)
gapic-generator-python
WANTED: ruby, swift, rust, elixir...
gapic-generator
(java, php, python, go,
csharp, node, ruby)
gapic-generator-kotlin
gapic-generator-go
gapic-generator-csharp
gapic-generator-typescript
One API
description
(Annotated
.proto files)
Many
language-
specific
client
libraries
Standard (Language-Independent) API Client Configuration
“Showcase” API verification
What can else we get from an API description format?
● Generated CLIs
● Generated Documentation
● API review and governance
● API management services
● Server frameworks and tools
● Generated mock servers
● Automatic testing
● API search and discovery
Manage Your Service With Endpoints
Develop, deploy and manage APIs on any Google Cloud Platform backend.
● User Authentication via JSON Web Token validation
● Logging and Monitoring
● API Keys
● Easy integration + deployment
Endpoints Architecture
GCE, GKE, Kubernetes or App Engine
Flexible
Environment Instance
GCE, GKE, Kubernetes or App Engine Flexible
Environment Instance (or off-GCP)
Extensible Service
Proxy Container
API Container
Google Service
Management API
User
Code
api
calls
gcloud
Config
deployment
Google Cloud
Console
Google Service
Control API
config Runtime
check & report
Load
balanci
ng
Stackdriver
Metrics &
logs
Metrics &
logs
visualized
Generate FileDescriptorSet
protoc kiosk.proto 
-I api-common-protos 
-I . 
--include_imports 
--include_source_info 
--descriptor_set_out=generated/kiosk_descriptor.pb 
--go_out=plugins=grpc:generated
Describing the Service
type: google.api.Service
config_version: 3
name: my-api.endpoints.my-gcp-project.cloud.goog
title: Kiosk gRPC API
apis:
- name: kiosk.Display
Starting Endpoints Proxy in Front of Application
gcloud endpoints services deploy service.yaml kiosk_descriptor.pb
./endpoints/START_ENDPOINTS_PROXY.sh my-gcp-project my-api <keyfile>
$ export KIOSK_PORT=8083
$ k list kiosks
FROM localhost:8083 LIST KIOSKS
rpc error: code = Unauthenticated
desc = Method doesn't allow
unregistered callers (callers
without established identity).
Please use API Key or other form of
API consumer identity to call this
API.
Starting Endpoints Proxy in Front of Application
$ export KIOSK_APIKEY=AIzaSy[...]bBo
$ k list kiosks
FROM localhost:8083 2018/09/21 19:08:25 Using API key: AIzaSy[...]bBo
LIST KIOSKS
id:1 name:"HTTP Kiosk" size:<width:1080 height:720 >
id:2 name:"HTTP Kiosk" size:<width:1080 height:720 >
Getting an API Key
Build a gRPC service, get a free REST API!
service Display {
rpc CreateKiosk(Kiosk) returns (Kiosk) {
option (google.api.http) = {post:"/v1/kiosks"};
}
rpc GetKiosk(GetKioskRequest) returns (Kiosk) {
option (google.api.http) =
{get: "/v1/kiosks/{id}" };
}
rpc DeleteKiosk(DeleteKioskRequest)
returns (google.protobuf.Empty) {
option (google.api.http) =
{ delete: "/v1/signs/{id}" };
}
[...]
}
Add REST annotations to your service
gRPC definitions with HTTP annotations
service Display {
rpc CreateKiosk(Kiosk) returns (Kiosk) {
}
rpc GetKiosk(GetKioskRequest) returns(Kiosk) {
}
rpc DeleteKiosk(DeleteKioskRequest)
returns (google.protobuf.Empty) {
}
[...]
}
gRPC definitions
# Add a kiosk
$ curl -d '{"name":"HTTP Kiosk", "size": { width: 1080, height: 720 } }' 
localhost:8082/v1/kiosks?key=AIzaSy[...]bBo
# Get kiosk
$ curl localhost:8082/v1/kiosks/1?key=AIzaSy[...]bBo
Now you can use HTTP+JSON!
Use Endpoints, get a free developer portal!
Build GraphQL interfaces to gRPC services
with rejoiner
BONUS: Call Google RPC APIs with HTTP/1 using gRPC Fallback
We’re in the Summer of Code!
Have a Slice of APIs with us!
And don’t miss: Swift for Tensorflow

More Related Content

What's hot (20)

ODP
nftables - the evolution of Linux Firewall
Marian Marinov
 
PPT
Introduction To Intrusion Detection Systems
Paul Green
 
PPTX
Berkeley Packet Filters
Kernel TLV
 
PPTX
Diameter Presentation
Beny Haddad
 
PDF
Project calico - introduction
Hazzim Anaya
 
PDF
Cilium + Istio with Gloo Mesh
Christian Posta
 
PPTX
Connected, Static & Dynamic Routes
NetProtocol Xpert
 
PPTX
Ospf
Joshua Fonseca
 
PDF
Ospf routing protocol
Edgardo Scrimaglia
 
PDF
Ripe71 FastNetMon open source DoS / DDoS mitigation
Pavel Odintsov
 
PPTX
Understanding NMAP
Phannarith Ou, G-CISO
 
PPTX
PIW ISE best practices
Sergey Kucherenko
 
PDF
Android Internals
Opersys inc.
 
PPT
Matrix Telecom Solutions: SETU VTEP - Fixed VoIP to T1/E1 PRI Gateway
Matrix Comsec
 
PPTX
IPSec and VPN
Abdullaziz Tagawy
 
PDF
Ccnp presentation day 4 sd-access vs traditional network architecture
SagarR24
 
PDF
Biznet GIO National Seminar on Digital Forensics
Yusuf Hadiwinata Sutandar
 
PDF
Operator Framework Overview
Rob Szumski
 
ODP
Tema 2 - Introducción a la Criptografía
Daniel Pecos Martínez
 
PPTX
K8s in 3h - Kubernetes Fundamentals Training
Piotr Perzyna
 
nftables - the evolution of Linux Firewall
Marian Marinov
 
Introduction To Intrusion Detection Systems
Paul Green
 
Berkeley Packet Filters
Kernel TLV
 
Diameter Presentation
Beny Haddad
 
Project calico - introduction
Hazzim Anaya
 
Cilium + Istio with Gloo Mesh
Christian Posta
 
Connected, Static & Dynamic Routes
NetProtocol Xpert
 
Ospf routing protocol
Edgardo Scrimaglia
 
Ripe71 FastNetMon open source DoS / DDoS mitigation
Pavel Odintsov
 
Understanding NMAP
Phannarith Ou, G-CISO
 
PIW ISE best practices
Sergey Kucherenko
 
Android Internals
Opersys inc.
 
Matrix Telecom Solutions: SETU VTEP - Fixed VoIP to T1/E1 PRI Gateway
Matrix Comsec
 
IPSec and VPN
Abdullaziz Tagawy
 
Ccnp presentation day 4 sd-access vs traditional network architecture
SagarR24
 
Biznet GIO National Seminar on Digital Forensics
Yusuf Hadiwinata Sutandar
 
Operator Framework Overview
Rob Szumski
 
Tema 2 - Introducción a la Criptografía
Daniel Pecos Martínez
 
K8s in 3h - Kubernetes Fundamentals Training
Piotr Perzyna
 

Similar to Creating Great REST and gRPC API Experiences (in Swift) (20)

PPT
Rapid java backend and api development for mobile devices
ciklum_ods
 
PDF
Networked APIs with swift
Tim Burks
 
PPTX
CocoaConf: The Language of Mobile Software is APIs
Tim Burks
 
PDF
apidays LIVE Helsinki - Implementing OpenAPI and GraphQL Services with gRPC b...
apidays
 
PPTX
ASP.NET Web API and HTTP Fundamentals
Ido Flatow
 
PPTX
11 asp.net web api
Michael Mieles Caballero
 
PPTX
SVQdotNET: Building APIs with OpenApi
Juan Luis Guerrero Minero
 
PPTX
Web Service
Ashwani kumar
 
PPTX
What I learned about APIs in my first year at Google
Tim Burks
 
PPTX
TechEvent Eclipse Microprofile
Trivadis
 
PDF
XML-RPC and SOAP (April 2003)
Kiran Jonnalagadda
 
PDF
RESTEasy
Massimiliano Dessì
 
PDF
Rest with Spring
Eugen Paraschiv
 
PDF
Python tools for testing web services over HTTP
Mykhailo Kolesnyk
 
PDF
May 2010 - RestEasy
JBug Italy
 
ODP
RESTing with JAX-RS
Ezewuzie Emmanuel Okafor
 
PDF
Build your APIs with apigility
Christian Varela
 
PDF
Session 8 Android Web Services - Part 1.pdf
EngmohammedAlzared
 
PPTX
ASP.NET WEB API Training
Chalermpon Areepong
 
Rapid java backend and api development for mobile devices
ciklum_ods
 
Networked APIs with swift
Tim Burks
 
CocoaConf: The Language of Mobile Software is APIs
Tim Burks
 
apidays LIVE Helsinki - Implementing OpenAPI and GraphQL Services with gRPC b...
apidays
 
ASP.NET Web API and HTTP Fundamentals
Ido Flatow
 
11 asp.net web api
Michael Mieles Caballero
 
SVQdotNET: Building APIs with OpenApi
Juan Luis Guerrero Minero
 
Web Service
Ashwani kumar
 
What I learned about APIs in my first year at Google
Tim Burks
 
TechEvent Eclipse Microprofile
Trivadis
 
XML-RPC and SOAP (April 2003)
Kiran Jonnalagadda
 
Rest with Spring
Eugen Paraschiv
 
Python tools for testing web services over HTTP
Mykhailo Kolesnyk
 
May 2010 - RestEasy
JBug Italy
 
RESTing with JAX-RS
Ezewuzie Emmanuel Okafor
 
Build your APIs with apigility
Christian Varela
 
Session 8 Android Web Services - Part 1.pdf
EngmohammedAlzared
 
ASP.NET WEB API Training
Chalermpon Areepong
 
Ad

More from Tim Burks (12)

PDF
Governing APIs at Scale
Tim Burks
 
PDF
Usable APIs at Scale
Tim Burks
 
PDF
Build your next REST API with gRPC
Tim Burks
 
PDF
Implementing OpenAPI and GraphQL services with gRPC
Tim Burks
 
PDF
Enforcing API Design Rules for High Quality Code Generation
Tim Burks
 
PDF
Taming Cloud APIs with Swift
Tim Burks
 
PDF
OpenAPI and gRPC Side by-Side
Tim Burks
 
PDF
Fast and Reliable Swift APIs with gRPC
Tim Burks
 
PDF
Build Great Networked APIs with Swift, OpenAPI, and gRPC
Tim Burks
 
PDF
Interpreting Objective C
Tim Burks
 
PDF
Deep Geek Diving into the iPhone OS and Frameworks
Tim Burks
 
PDF
Building Open Radar
Tim Burks
 
Governing APIs at Scale
Tim Burks
 
Usable APIs at Scale
Tim Burks
 
Build your next REST API with gRPC
Tim Burks
 
Implementing OpenAPI and GraphQL services with gRPC
Tim Burks
 
Enforcing API Design Rules for High Quality Code Generation
Tim Burks
 
Taming Cloud APIs with Swift
Tim Burks
 
OpenAPI and gRPC Side by-Side
Tim Burks
 
Fast and Reliable Swift APIs with gRPC
Tim Burks
 
Build Great Networked APIs with Swift, OpenAPI, and gRPC
Tim Burks
 
Interpreting Objective C
Tim Burks
 
Deep Geek Diving into the iPhone OS and Frameworks
Tim Burks
 
Building Open Radar
Tim Burks
 
Ad

Recently uploaded (20)

PDF
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
PDF
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
PPTX
Comprehensive Guide: Shoviv Exchange to Office 365 Migration Tool 2025
Shoviv Software
 
PDF
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PDF
Executive Business Intelligence Dashboards
vandeslie24
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PPTX
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
PDF
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
PPTX
Human Resources Information System (HRIS)
Amity University, Patna
 
PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
PPTX
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
PPTX
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
PDF
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
PPTX
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
PDF
Efficient, Automated Claims Processing Software for Insurers
Insurance Tech Services
 
DOCX
Import Data Form Excel to Tally Services
Tally xperts
 
PPTX
Feb 2021 Cohesity first pitch presentation.pptx
enginsayin1
 
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
Comprehensive Guide: Shoviv Exchange to Office 365 Migration Tool 2025
Shoviv Software
 
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
Executive Business Intelligence Dashboards
vandeslie24
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
Human Resources Information System (HRIS)
Amity University, Patna
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
Writing Better Code - Helping Developers make Decisions.pptx
Lorraine Steyn
 
Efficient, Automated Claims Processing Software for Insurers
Insurance Tech Services
 
Import Data Form Excel to Tally Services
Tally xperts
 
Feb 2021 Cohesity first pitch presentation.pptx
enginsayin1
 

Creating Great REST and gRPC API Experiences (in Swift)

  • 1. Creating Great REST and gRPC API Experiences (in Swift) Tim Burks Google
  • 2. October 4, 2000 CL 23852 by jeff ProtocolBuffer, a class for encoding hierarchical data in a compact binary form... Co-designed and Rev. by Sanjay
  • 11. Protocol Buffers a language-neutral, platform-neutral, extensible mechanism for serializing structured data.
  • 12. “Protocol Buffers” means several things 1. A serialization mechanism 2. An interface description language 3. A methodology
  • 13. A Serialization Mechanism An encoded message is 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
  • 14. An Interface Definition Language syntax = "proto3"; package echo; // The message used for echo requests and responses. message EchoMessage { string text = 1; }
  • 15. A Methodology % protoc echo.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.
  • 16. echo.pb.swift // DO NOT EDIT. // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: echo.proto // // For information on using the generated types, please see the documenation: // https://github.com/apple/swift-protobuf/ ... /// The message used for echo requests and responses. struct Echo_EchoMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. var text: String = String() var unknownFields = SwiftProtobuf.UnknownStorage() init() {} } // MARK: - Code below here is support for the SwiftProtobuf runtime.
  • 17. A Data Definition Language syntax = "proto3"; package models; message User { string id = 1; string name = 2; repeated PlantList plantLists = 3; } message PlantList { string id = 1; string name = 2; repeated PlantListItem plants = 11; } message PlantListItem { string id = 1; string botanical_name = 2; }
  • 18. 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)") } } }
  • 19. Interface Builder for Data message Person { string name = 1; int32 id = 2; string email = 3; message PhoneNumber { string number = 1; } repeated PhoneNumber phone = 4; } Interface Builder: Developers specify their interfaces using a special tool, tooling compiles and integrates that into their apps. Protocol Buffers: Developers specify their data structures using a special language, tooling compiles and integrates that into their apps.
  • 20. Let’s talk about Networked APIs 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.”
  • 21. API Styles 1. Remote Procedure Call (RPC) 2. Representational State Transfer (REST)
  • 22. An RPC is just a function call. service Echo { // Immediately returns an echo of a request. rpc Get(EchoRequest) returns (EchoResponse) {} }
  • 23. 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
  • 24. 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)
  • 25. 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).
  • 26. 1. HTTP/HTTPS a. Paths describe resources (nouns) b. HTTP verbs describe actions 2. JSON Payloads REST in Practice
  • 27. OpenAPI Industry standard format for describing for REST APIs Originally designed for documentation, now with many other applications: API Authoring, Validation, Documentation, Analysis, Search, Testing, Mocking, Management, Code Generation
  • 28. 2010-11: Google API Discovery Format
  • 29. Discovery Format Code Generators
  • 34. Authorization: How do we tell an API server that it’s ok to respond to our requests? 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?
  • 35. 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
  • 36. 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.
  • 37. 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 and sign it with the account credentials. 3. POST the signed JWT to the Google Account Service and get a token! See ServiceAccountTokenProvider.swift.
  • 38. Aside: Build an HTTP server with swift-server/http
  • 39. ● REST APIs ○ Discovery Format ○ 250+API descriptions ○ 10+ generators ● gRPC APIs ○ Protocol Buffer Language ○ 40+ gRPC-based APIs ○ 7+ target languages
  • 40. gRPC Open-Source messaging system based on Google’s internal API architecture. Used for code and documentation generation, API management, and support services for APIs and microservices running at very large scale.
  • 41. gRPC is owned by the Cloud Native Computing Foundation
  • 42. gRPC Adoption Microservices: in data centres Streaming telemetry from network devices Client Server communication/Internal APIs Mobile Apps
  • 43. gRPC Transport Mechanism Client → Server Server → Client Initial Metadata MsgMsg End of Stream Status & Trailing Metadata Initial Metadata MsgMsg Msg HTTP/2
  • 47. Build a Swift client and service with gRPC https://github.com/grpc/gr pc-swift/wiki/Try-gRPC-Swi ft-in-a-Google-Compute-Eng ine-VM or just https://goo.gl/ux4Txh
  • 48. 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; }
  • 49. 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 } } }
  • 50. 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)") }
  • 51. 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() } }
  • 52. 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) } }
  • 53. 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) }
  • 54. 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() } }
  • 55. Why generate client libraries for APIs? Make it easier to use Google APIs. ● Hide implementation details from API consumers. ● Develop API clients faster. ● Improve API client quality. ○ Better performance ○ Better consistency ○ Fewer bugs
  • 57. GAPIC Customers Google Cloud APIs Google Ads APIs …other Google teams …external API producers?
  • 58. GAPIC Features and Benefits ● Usability: ○ Trivial getting-started experience ○ Flattening ○ Natural paging ○ Long-running operations ○ Sample code for every method ○ Resource name types (e.g. for /projects/{project}/topics/{topic}) ● Performance: ○ Batching ● Reliability: ○ Automatic retries
  • 59. Trivial Getting-Started Experience GAPIC client: Channel channel = NettyChannelBuilder.forAddress(API_ENTRY, API_PORT).build(); List<ClientInterceptor> interceptors = new ArrayList<>(); GoogleCredentials credentials = GoogleCredentials.getApplicationDefault(); interceptors.add( ChannelFactory.credentialInterceptor(credentials)); LoggingService stub = LoggingServiceGrpc.newBlockingStub(channel, interceptors); gRPC: LoggingClient client = LoggingClient.create();
  • 60. Automatic Retry and Flattening GAPIC client: LoggingService stub = ...; // Note: this only does a simple retry, exponential backoff // is more complex DeleteLogRequest request = DeleteLogRequest.newBuilder() .setLogName(LOG_NAME) .build(); for (int i = 0; i < MAX_RETRY; i++) { try { stub.deleteLog(request); } catch (RpcException e) { if (i == MAX_RETRY) throw e; } } gRPC: LoggingClient client = LoggingClient.create(); client.deleteLog(LOG_NAME);
  • 61. Natural Pagination GAPIC client: LoggingService stub = ...; ListLogsRequest request = ListLogsRequest.newBuilder() .setParentName("projects/" + PROJECT_ID) .build(); while (true) { ListLogsResponse response = stub.listLogs(request); for (Log log : response.getLogsList()) { System.out.printf("Log: %s%n", log.getDisplayName()); } String nextPageToken = response.getNextPageToken(); if (nextPageToken != null) { request = ListLogsRequest.newBuilder() .setPageToken(nextPageToken).build(); } else { break; } } gRPC: LoggingClient client = LoggingClient.create(); ParentNameOneOf parent = ParentNameOneOf.from(ProjectName.create(PROJECT_ID)); for (Log log : client.listLogs(PARENT).iterateAll()) { System.out.printf("Log: %s%n", log.getDisplayName()); }
  • 62. Long-Running Operations SpeechClient speechClient = SpeechClient.create(); OperationFuture<LongRunningRecognizeResponse> recognizeOperation = speechClient.longRunningRecognizeAsync(config, audio); … LongRunningRecognizeResponse response = recognizeOperation.get(); ● Java: OperationFuture ○ Polls the service until the LRO is done ○ Provides metadata as the LRO is in progress ○ Provides the final result
  • 63. Resource Name Types GAPIC client: PublisherService stub = ...; CreateTopicRequest request = CreateTopicRequest.newBuilder() .setTopic("projects/my-project/topics/my-topic") .build(); Topic response = stub.createTopic(request); gRPC: TopicAdminClient topicAdminClient = TopicAdminClient.create(); TopicName name = TopicName.create("my-project", "my-topic"); Topic response = topicAdminClient.createTopic(name);
  • 65. GAPIC Project Architecture (hosted at github.com/googleapis) gapic-generator-python WANTED: ruby, swift, rust, elixir... gapic-generator (java, php, python, go, csharp, node, ruby) gapic-generator-kotlin gapic-generator-go gapic-generator-csharp gapic-generator-typescript One API description (Annotated .proto files) Many language- specific client libraries
  • 66. Standard (Language-Independent) API Client Configuration
  • 68. What can else we get from an API description format? ● Generated CLIs ● Generated Documentation ● API review and governance ● API management services ● Server frameworks and tools ● Generated mock servers ● Automatic testing ● API search and discovery
  • 69. Manage Your Service With Endpoints Develop, deploy and manage APIs on any Google Cloud Platform backend. ● User Authentication via JSON Web Token validation ● Logging and Monitoring ● API Keys ● Easy integration + deployment
  • 70. Endpoints Architecture GCE, GKE, Kubernetes or App Engine Flexible Environment Instance GCE, GKE, Kubernetes or App Engine Flexible Environment Instance (or off-GCP) Extensible Service Proxy Container API Container Google Service Management API User Code api calls gcloud Config deployment Google Cloud Console Google Service Control API config Runtime check & report Load balanci ng Stackdriver Metrics & logs Metrics & logs visualized
  • 71. Generate FileDescriptorSet protoc kiosk.proto -I api-common-protos -I . --include_imports --include_source_info --descriptor_set_out=generated/kiosk_descriptor.pb --go_out=plugins=grpc:generated
  • 72. Describing the Service type: google.api.Service config_version: 3 name: my-api.endpoints.my-gcp-project.cloud.goog title: Kiosk gRPC API apis: - name: kiosk.Display
  • 73. Starting Endpoints Proxy in Front of Application gcloud endpoints services deploy service.yaml kiosk_descriptor.pb ./endpoints/START_ENDPOINTS_PROXY.sh my-gcp-project my-api <keyfile>
  • 74. $ export KIOSK_PORT=8083 $ k list kiosks FROM localhost:8083 LIST KIOSKS rpc error: code = Unauthenticated desc = Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API. Starting Endpoints Proxy in Front of Application
  • 75. $ export KIOSK_APIKEY=AIzaSy[...]bBo $ k list kiosks FROM localhost:8083 2018/09/21 19:08:25 Using API key: AIzaSy[...]bBo LIST KIOSKS id:1 name:"HTTP Kiosk" size:<width:1080 height:720 > id:2 name:"HTTP Kiosk" size:<width:1080 height:720 > Getting an API Key
  • 76. Build a gRPC service, get a free REST API!
  • 77. service Display { rpc CreateKiosk(Kiosk) returns (Kiosk) { option (google.api.http) = {post:"/v1/kiosks"}; } rpc GetKiosk(GetKioskRequest) returns (Kiosk) { option (google.api.http) = {get: "/v1/kiosks/{id}" }; } rpc DeleteKiosk(DeleteKioskRequest) returns (google.protobuf.Empty) { option (google.api.http) = { delete: "/v1/signs/{id}" }; } [...] } Add REST annotations to your service gRPC definitions with HTTP annotations service Display { rpc CreateKiosk(Kiosk) returns (Kiosk) { } rpc GetKiosk(GetKioskRequest) returns(Kiosk) { } rpc DeleteKiosk(DeleteKioskRequest) returns (google.protobuf.Empty) { } [...] } gRPC definitions
  • 78. # Add a kiosk $ curl -d '{"name":"HTTP Kiosk", "size": { width: 1080, height: 720 } }' localhost:8082/v1/kiosks?key=AIzaSy[...]bBo # Get kiosk $ curl localhost:8082/v1/kiosks/1?key=AIzaSy[...]bBo Now you can use HTTP+JSON!
  • 79. Use Endpoints, get a free developer portal!
  • 80. Build GraphQL interfaces to gRPC services with rejoiner
  • 81. BONUS: Call Google RPC APIs with HTTP/1 using gRPC Fallback
  • 82. We’re in the Summer of Code!
  • 83. Have a Slice of APIs with us!
  • 84. And don’t miss: Swift for Tensorflow