Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Move fast, don't break your API
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Amber Feng
September 30, 2014
Programming
18
54k
Move fast, don't break your API
Amber Feng
September 30, 2014
Tweet
Share
More Decks by Amber Feng
See All by Amber Feng
Pixels & Tactics
amfeng
1
10k
Building Stripe's API
amfeng
35
53k
Other Decks in Programming
See All in Programming
Angular-Apps smarter machen mit Gen AI: Lokal und offlinefähig - Hands-on Workshop!
christianliebel
PRO
0
130
脱 雰囲気実装!AgentCoreを良い感じにWEBアプリケーションに組み込むために
takuyay0ne
3
380
「接続」—パフォーマンスチューニングの最後の一手 〜点と点を結ぶ、その一瞬のために〜
kentaroutakeda
3
1.7k
安いハードウェアでVulkan
fadis
0
730
エンジニアの「手元の自動化」を加速するn8n 2026.02.27
symy2co
0
170
技術検証結果の整理と解析をAIに任せよう!
keisukeikeda
0
130
S3ストレージクラスの「見える」「ある」「使える」は全部違う ─ 体験から見た、仕様の深淵を覗く
ya_ma23
0
880
Everything Claude Code OSS詳細 — 5層構造の中身と導入方法
targe
0
150
SourceGeneratorのマーカー属性問題について
htkym
0
210
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
2
500
Laravel Nightwatchの裏側 - Laravel公式Observabilityツールを支える設計と実装
avosalmon
1
140
ロボットのための工場に灯りは要らない
watany
11
3.1k
Featured
See All Featured
Into the Great Unknown - MozCon
thekraken
40
2.3k
Test your architecture with Archunit
thirion
1
2.2k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
89
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
150
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
980
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
860
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.2k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
180
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
180
Writing Fast Ruby
sferik
630
63k
Context Engineering - Making Every Token Count
addyosmani
9
770
Transcript
MOVE FAST, DON'T BREAK YOUR API AMBER FENG @amfeng
None
LET'S BUILD AN API!
post '/v1/charges' do card_number = params[:card_number] amount = params[:amount] charge
= create_charge(card_number, amount) json { id: charge.id, amount: charge.amount card_number: charge.redacted_card_number, success: charge.success } end
post '/v1/charges' do ... unless card_number.length == 16 return {error:
"Invalid card number."} end unless amount > 0 and amount <= CHARGE_MAX return {error: "Invalid amount."} end ... end
post '/v1/charges' do api_key = get_api_key user = User.find_by_key(api_key) unless
user return {error: "Invalid API key."} end ... end
curl https://stripe.com/v1/charges -u API_KEY -d card_number=4242424242424242 -d amount=100 => {
id: "ch_xxx", amount: 100, card_number: "*4242", success: true }
None
WHAT NEXT?
WHAT NEXT? MORE ENDPOINTS
WHAT NEXT? MORE ENDPOINTS MORE FUNCTIONALITY
WHAT NEXT? MORE ENDPOINTS MORE FUNCTIONALITY MORE CHANGES
WHAT NEXT? MORE ENDPOINTS MORE FUNCTIONALITY MORE CHANGES MORE PROBLEMS
LARGE, TANGLED CODEBASE
COPY-PASTA
ERROR-PRONE DEPENDENCIES
"CRAP, I FORGOT TO UPDATE THE DOCS!" — Everyone ever
HOW DO WE MAKE IT BETTER?
DESIGN FOR YOURSELF, TOO
SEPARATE DIFFERENT LAYERS OF LOGIC
Authentication Validation Endpoint-specific logic Constructing the response Error handling
Error handler Authenticator API logic
use ErrorHandler use Authenticator get '/v1/charges/:id' do user = env.user
id = params[:id] unless user.get_charge(id) raise UserError.new("No charge #{id}!") end end
APIMethods & APIResources
class ChargeCreateMethod < AbstractAPIMethod required :amount, :integer required :card_number, :string
resource ChargeAPIResource def execute create_charge(amount, card_number) end end
class ChargeAPIResource < AbstractAPIResource required :id, :string required :amount, :integer
required :card_number, :string required :success, :boolean def describe_card_number charge.redacted_card_number end end
post '/v1/charges' do APIMethod::ChargeCreateMethod.invoke end get '/v1/charges' do APIMethod::ChargeRetrieveMethod.invoke end
MAKE IT HARD TO MESS UP
class ChargeCreateMethod < AbstractAPIMethod required :amount, :integer required :card_number, :string
document :amount, "Amount, in cents." document :card_number, "The card number." ... end
HIDE BACKWARDS COMPATIBILITY
<todo: tweet>
def execute if !user.version_1? && params[:amount] raise UserError.new("Invalid param.") end
... if !user.version_1? response.delete(:amount) end end
GATES
- :version: 2014-09-24 :new_gates: - :gate: allows_amount :description: >- Sending
amount is now deprecated.
def execute if !user.gating(:allows_amount) && params[:amount] raise UserError.new("Invalid param.") end
... if !user.gating(:allows_amount) response.delete(:amount) end end
COMPATIBILITY LAYERS
Request compatibility API logic Construct API response Response compatibility
IN THE REAL WORLD
106 ENDPOINTS 65 VERSIONS 6 API CLIENTS
DESIGN FOR YOURSELF: SEPARATE LAYERS OF LOGIC MAKE IT HARD
TO MESS UP HIDE BACKWARDS COMPAT
WHAT ELSE?
NOT SURE. (WE'RE STILL FIGURING IT OUT AS WE GO.)
THANKS! (: @amfeng