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
Reacting to Change - API Days 2014
Search
Kyle Fuller
December 02, 2014
Technology
220
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Reacting to Change - API Days 2014
Kyle Fuller
December 02, 2014
More Decks by Kyle Fuller
See All by Kyle Fuller
Design APIs and deliver what you promised
kylef
0
150
Preparing for the future of API Description Languages
kylef
0
130
Resilient API Design
kylef
1
360
Building a Swift Web API and Application Together
kylef
2
2.2k
Testing without Xcode - CMD+U 2016
kylef
0
300
End-to-end: Building a Web Service in Swift (MCE 2016)
kylef
2
510
Designing APIs for Humans - Write the Docs 2016
kylef
0
370
Embracing Change - MBLTDev 2015
kylef
3
710
Practical Declarative Programming (360 iDev 2015)
kylef
3
570
Other Decks in Technology
See All in Technology
NW運用でNWトポロジ可視化ツールに期待すること/shumoku-meetup1
corestate55
2
110
Amazon Quick on DesktopがIAM Identity Centerで動かない理由
yukiogawa
0
170
「図書館」という名前のままでいいのか -Code4Lib JAPANカンファレンス2026 アンカンファレンス報告- / Code4Lib JAPAN Conference 2026: Unconference Report
ykiyota
0
170
Code4Lib JAPANカンファレンス2026 開会挨拶 / Code4Lib JAPAN Conference 2026: Opening Remarks
ykiyota
0
340
AIとペアプロを始める。人とのペアプロをやめる。ペアプロの良さを改めて知る。もっと好きになった。 / Rediscovering Pair Programming
honyanya
1
350
AI時代に顧客へ最速で価値を 届けるための試行錯誤 〜「AI × マネジメント」領域におけるmentoのケース〜
posterkeisuke
0
110
安心して変更できるWebフロントエンドの作り方
pirosikick
4
1.2k
GoCon2026 - Open Source, Open World
sanposhiho
4
3.3k
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
3
1.3k
GoにおけるFFIのこれまでとこれから
goccy
5
2.5k
20260912_スクラムにジェネラリストは必要か
ryugen04
0
360
AI活用の現在地、 ちゃんと見えてますか?/XPfest-2026
visional_engineering_and_design
0
200
Featured
See All Featured
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
The Language of Interfaces
destraynor
162
27k
Balancing Empowerment & Direction
lara
6
1.3k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
520
How GitHub (no longer) Works
holman
316
150k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
880
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
Accessibility Awareness
sabderemane
1
210
A Soul's Torment
seathinner
7
3.6k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Designing for Timeless Needs
cassininazir
1
470
Transcript
REACTING TO CHANGE ! KYLE FULLER
BUILDING better API CLIENTS
None
None
DOZENS of APPS
HTTP / APIS
THERE’S AN API
COMPONENTS OF AN API CLIENT
perform(.RetrieveArticles) { result in switch result { case .Success(let representor):
/* We've got some articles */ case .Error(let error): /* We hit an error */ } }
FOUNDATION
NSURLSession OR NSURLConnection
NSURLRequest
NSURLHTTPResponse
SIMPLE...
HTTP SEMANTICS
SERIALISATION (JSON)
CONVERT to VALUE-MODELS
struct Article { let title:String let body:String let author:Author let
image:[NSURL] } struct Author { let name:String let twitter:String }
articles[0]["author"]["name"]
"/articles"
"name"
"nme"
- age + birthday
None
None
MAPPING
HTTP JSON MODEL MAPPING TESTS (STUBS & FIXTURES) DOMAIN LOGIC?
$ cloc **Model**.{h,m} **API**.{h,m} 95 text files. 83 unique files.
0 files ignored. ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- Objective C 51 1420 499 5598 C/C++ Header 32 258 480 479 ------------------------------------------------------------------------------- SUM: 83 1678 979 6077 -------------------------------------------------------------------------------
6077 LINES OF CODE
ANDROID
15,000 LINES OF CODE
WINDOWS PHONE
20,000 LINES OF CODE
...
30,000 LINES OF CODE
BUILDING an API CLIENT
DOMAIN-SPECIFIC
INTEGRATED
MIXING PROTOCOL SEMANTICS
WHAT DOES THE API LOOK LIKE?
None
None
None
GETTING STARTED
TESTS
MOCK
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { return ([request.URL.host isEqualToString:@"trunk.cocoapods.org"] && [request.URL.path isEqualToString:@"/api/v1/sessions"]);
} withStubResponse:^ OHHTTPStubsResponse *(NSURLRequest *request) { NSString *fixture = OHPathForFileInBundle(@"sessions.json", nil); NSDictionary *headers = @{ @"Content-Type": @"application/json" }; return [OHHTTPStubsResponse responseWithFileAtPath:fixture statusCode:200 headers:headers]; }];
{ "created_at": "2014-04-21 23:08:00 +0200", "email": "
[email protected]
", "name": "Kyle Fuller",
"sessions": [ { "created_at": "2014-05-04 15:20:19 +0200", "valid_until": "2014-09-09 15:20:19 +0200", "verified": false }, { "created_at": "2014-05-04 15:20:20 +0200", "valid_until": "2014-09-09 15:20:20 +0200", "verified": true } ] }
AND REPEAT
None
CAN’T WE USE THIS?
UNDERSTANDABLE by machines
POWERING YOUR TESTS with API BLUEPRINT
pod `CCLRequestReplay`
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { return ([request.URL.host isEqualToString:@"trunk.cocoapods.org"] && [request.URL.path isEqualToString:@"/api/v1/sessions"]);
} withStubResponse:^ OHHTTPStubsResponse *(NSURLRequest *request) { NSString *fixture = OHPathForFileInBundle(@"sessions.json", nil); NSDictionary *headers = @{ @"Content-Type": @"application/json" }; return [OHHTTPStubsResponse responseWithFileAtPath:fixture statusCode:200 headers:headers]; }]; [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { return ([request.URL.host isEqualToString:@"trunk.cocoapods.org"] && [request.URL.path isEqualToString:@"/api/v1/pods"]); } withStubResponse:^ OHHTTPStubsResponse *(NSURLRequest *request) { NSString *fixture = OHPathForFileInBundle(@"pods.json", nil); NSDictionary *headers = @{ @"Content-Type": @"application/json" }; return [OHHTTPStubsResponse responseWithFileAtPath:fixture statusCode:200 headers:headers]; }]; [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { return ([request.URL.host isEqualToString:@"trunk.cocoapods.org"] && [request.URL.path isEqualToString:@"/api/v1/pod/../owners"]); } withStubResponse:^ OHHTTPStubsResponse *(NSURLRequest *request) { NSString *fixture = OHPathForFileInBundle(@"pod-querykit-owners.json", nil); NSDictionary *headers = @{ @"Content-Type": @"application/json" }; return [OHHTTPStubsResponse responseWithFileAtPath:fixture statusCode:200 headers:headers]; }]; ...
{ "created_at": "2014-04-21 23:08:00 +0200", "email": "
[email protected]
", "name": "Kyle Fuller",
"sessions": [ { "created_at": "2014-05-04 15:20:19 +0200", "valid_until": "2014-09-09 15:20:19 +0200", "verified": false }, { "created_at": "2014-05-04 15:20:20 +0200", "valid_until": "2014-09-09 15:20:20 +0200", "verified": true } ] } { "name": "QueryKit", "version": "0.8.3", "authors": { "Kyle Fuller": "
[email protected]
" }, "social_media_url": "http://twitter.com/kylefuller", "source": { "git": "https://github.com/QueryKit/QueryKit.git", "tag": "0.8.3" }, "source_files": [ "QueryKit/*.{h}", "QueryKit/ObjectiveC/*.{h,m}" ], "requires_arc": true } ...
let URL = NSBundle.mainBundle().URIForResource("palaver", withExtension:"apib.json") requestReplayManager.addRecordings(fromBlueprintURL:URL, error:nil)
GET /sessions
None
EMBRACE CHANGE
None
WE MADE A MISTAKE.
WE WANT TO CHANGE... ENDPOINT URI.
NEGOTIATE AT RUN-TIME
WE WANT TO CHANGE... PAGINATION LOGIC.
FOLLOWING LINKS
TRANSITION BETWEEN STATES
"Paging is achieved with the published_before parameter."
published_before
[ { "published_date": "2013-04-30T16:05:45+00:00", ... } ]
GET /articles?published_before=2013-04-30T16:05:45+00:00
SERVER LOGIC
Next Page = <some URI>
Prevent BREAKING CHANGES
BUILDING BETTER CLIENTS from THE API
FLEXIBILITY
CASCADED REQUESTS
GET /categories GET /authors GET /articles
BANDWIDTH
LARGE DATA
$ curl -I http://api.something.com/articles HTTP/1.1 200 OK Content-Type: application/json Content-Length:
12524998
BREAK IT UP
PAGINATION
/list VS /list/detail
USE Last-Modified
USE Cache-Control
USE STANDARDS
LET’S BUILD BETTER APIS TOGETHER
KYLE FULLER