Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Envoy Mobile & the upcoming networking revolution
Search
Michael Rebello
November 29, 2019
Programming
130
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Envoy Mobile & the upcoming networking revolution
Talk given at Swiftable in Buenos Aires, Argentina in November 2019.
Michael Rebello
November 29, 2019
Other Decks in Programming
See All in Programming
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.2k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
210
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
430
The Rails Doctrine Decade
koic
2
590
気持ちぃ〜角丸 Squircle
ryu1013
0
310
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
280
残高管理から台帳サービスへの進化
artoy
1
200
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
370
TechTown - Creating Composable Callables in Contemporary C++
rollbear
0
130
3回つくってわかった、 定期実行ジョブ基盤の本質情報
takai
0
510
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.9k
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
250
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1033
470k
New Earth Scene 8
popppiees
4
2.7k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
560
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
How to Think Like a Performance Engineer
csswizardry
28
2.9k
The Cult of Friendly URLs
andyhume
79
7k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Embracing the Ebb and Flow
colly
88
5.2k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.9k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
67k
Between Models and Reality
mayunak
4
500
Transcript
Envoy Mobile & the upcoming networking revolution Michael Rebello @rebello95
Swiftable (Buenos Aires) - November 2019
Service Networking Networking iOS
Service Flask, etc. URLSession iOS
Service Library X Library X iOS
Service Envoy Envoy Mobile iOS
Let’s talk about what data we send, then come back
to how we send it.
Early API workflow at Lyft Tech spec handwritten.swift handwritten.kt handwritten.py/.go
let params: [String: Any] = [ "lat": position.latitude, "lng": position.longitude,
"some_param": true, ] client.request(.post, "/foo", parameters: params) { result in … } Early APIs at Lyft
• Handwritten code led to mistakes/typos Problems
iOS Server { “key_a”: “hello” } Programming errors
iOS Server { “key_a”: “hello” } Android { “kye_a”: “hello”
} Programming errors
iOS Server { “key_a”: “hello” } Android { “kye_a”: “hello”
} if (android): else: Programming errors
• Handwritten code led to mistakes/typos • No visibility into
deserialization failures Problems
import Mapper extension FooResponse: Mappable { init(map: Mapper) throws {
self.placeID = try map.from("place_id") let item: String? = map.optionalFrom("items") self.placeDisplay = map.optionalFrom("display.lien_two") } } Deserialization failures
import Mapper extension FooResponse: Mappable { init(map: Mapper) throws {
self.placeID = try map.from("place_id") let item: String? = map.optionalFrom("items") self.placeDisplay = map.optionalFrom("display.lien_two") } } Deserialization failures
import Mapper extension FooResponse: Mappable { init(map: Mapper) throws {
self.placeID = try map.from("place_id") let item: String? = map.optionalFrom("items") self.placeDisplay = map.optionalFrom("display.lien_two") } } Deserialization failures
• Handwritten code led to mistakes/typos • No visibility into
deserialization failures • No single source of truth Problems
YAML integration
paths: /foo: post: parameters: - in: body schema: $ref: '#/definitions/FooRequest'
responses: 200: schema: $ref: '#/definitions/FooResponse' YAML definitions
• Manual code generation for Android • No integration on
iOS or services • Still inconsistencies across platforms • No single source of truth YAML results
Consistency
We needed a source of truth that provided guarantees for
the behavior of any given API.
IDL & protobuf
Interface Definition Language IDL
Old workflow Tech spec handwritten.swift handwritten.kt handwritten.py/.go
Envisioned workflow Tech spec IDL repo foo_api.swift foo_api.kt foo_api.py/.go foo_api.proto
Platform-neutral IDL for defining and serializing APIs. Protocol buffers (“protobufs”)
• Simple to write • Open-source generators available for most
popular languages • JSON support • Optimized wire encoding Why protobuf?
Intro to protobuf
message FooRequest { … } message FooResponse { int64 id
= 1; string first_name = 2; } service Foo { rpc UpdateFoo(FooRequest) returns (FooResponse) { option (http.http_options).path = "/foo"; option (http.http_options).method = "POST"; } } Protobuf definition
message FooRequest { … } message FooResponse { int64 id
= 1; string first_name = 2; } service Foo { rpc UpdateFoo(FooRequest) returns (FooResponse) { option (http.http_options).path = "/foo"; option (http.http_options).method = "POST"; } } Protobuf messages
message FooRequest { … } message FooResponse { int64 id
= 1; string first_name = 2; } service Foo { rpc UpdateFoo(FooRequest) returns (FooResponse) { option (http.http_options).path = "/foo"; option (http.http_options).method = "POST"; } } Protobuf fields
message FooRequest { … } message FooResponse { int64 id
= 1; string first_name = 2; } service Foo { rpc UpdateFoo(FooRequest) returns (FooResponse) { option (http.http_options).path = "/foo"; option (http.http_options).method = "POST"; } } Protobuf services
message FooRequest { … } message FooResponse { int64 id
= 1; string first_name = 2; } service Foo { rpc UpdateFoo(FooRequest) returns (FooResponse) { option (http.http_options).path = "/foo"; option (http.http_options).method = "POST"; } } Protobuf RPCs (Remote Procedure Calls)
message FooRequest { … } message FooResponse { int64 id
= 1; string first_name = 2; } service Foo { rpc UpdateFoo(FooRequest) returns (FooResponse) { option (http.http_options).path = "/foo"; option (http.http_options).method = "POST"; } } Protobuf annotations
IDL pipeline /api/foo.proto Generators +7 others foo.go foo.py foo.kt foo.swift
IDL pipeline /api/foo.proto Generators +7 others foo.go foo.py foo.kt foo.swift
FooV1API library foo-v1-api library
Using protobuf in Swift
// Modules/FooV1API/FooAPI.swift public struct FooRequest: Codable, Equatable { … }
public struct FooResponse: Codable, Equatable { public let id: Int64 public let firstName: String } Generated models
// Modules/FooV1API/FooAPI.swift import RxSwift public protocol FooAPI { func updateFoo(_
request: FooRequest) -> Single<Result<FooResponse, FooAPIError>> } public struct FooClientAPI: FooAPI { // Abstracted implementation } Generated APIs
// Modules/FooV1API/FooAPI.swift import RxSwift public protocol FooAPI { func updateFoo(_
request: FooRequest) -> Single<Result<FooResponse, FooAPIError>> } public struct FooClientAPI: FooAPI { // Abstracted implementation } Generated APIs
// Modules/FooV1APIMock/FooAPI.swift open class FooMockAPI: FooAPI { open lazy var
mockUpdateFoo: (FooRequest) -> Result<FooResponse, FooAPIError> = { … } open func updateFoo(_ request: FooRequest) -> Single<Result<FooResponse, FooAPIError>> { … } } Generated mocks
// Modules/FooFeatureModule/FooFeature.swift getFooClientAPI() .updateFoo(FooRequest(...)) .subscribe({ result in switch result {
case .success(let response): // Consume the response case .failure(let error): // Handle the failure } }) .disposed(by: self.disposeBag) Using APIs
★ Single source of truth for all APIs ★ Consistent
interfaces across platforms ★ Ergonomic generated code on all platforms ★ Highly testable ★ Wire format fully abstracted Results
Optimizing transport: Content negotiation
Client Service JSON request Existing system JSON response
Client Service JSON request Content-Type: json Accept: x-protobuf,json Content negotiation
Middleware (service) JSON > Protobuf Protobuf request Content-Type: x-protobuf Protobuf response Content-Type: x-protobuf Middleware (service) No change Protobuf response Content-Type: x-protobuf
JSON Protobuf
• 40%+ reduction in payload sizes • Faster response times
• Higher success rates • Transparent to engineers Wins from protobuf
What if we want to change how we send data
rather than what we send?
C++ proxy that abstracts networking from services
Envoy service mesh Service A Proxy Service B Proxy HTTP/1.1,
HTTP/2, gRPC, etc. HTTP/1.1, HTTP/2, gRPC, etc.
Envoy filters Common functionality executed on each request or response
Envoy filters Service A Filter Add auth headers Filter gzip
request Proxy Proxy Filter Unzip payload Filter Validate auth headers Service B
Envoy service mesh + front proxy Service A Proxy Service
B Proxy HTTP/1.1, HTTP/2, gRPC, etc. Client Proxy
Service Library X Library X iOS
None
Service A Proxy Service B Proxy Proxy Client Mobile
• 1 network stack for all platforms • Write filter
functionality once, deploy everywhere • Support new protocols like HTTP/3 (QUIC) • Consistent stats/monitoring across all platforms Envoy Mobile!
Stats Real-time requests from Envoy Mobile on Lyft rider (alpha)
Envoy Mobile will revolutionize how we enable network consistency across
all platforms.
envoy-mobile.github.io @rebello95 Join us!