Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Move fast, don't break your API
Search
Amber Feng
September 30, 2014
Programming
18
53k
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
9.9k
Building Stripe's API
amfeng
35
52k
Other Decks in Programming
See All in Programming
無秩序からの脱却 / Emergence from chaos
nrslib
2
12k
WebRTC、 綺麗に見るか滑らかに見るか
sublimer
1
140
俺流レスポンシブコーディング 2025
tak_dcxi
13
7.7k
MAP, Jigsaw, Code Golf 振り返り会 by 関東Kaggler会|Jigsaw 15th Solution
hasibirok0
0
210
Level up your Gemini CLI - D&D Style!
palladius
1
170
ZOZOにおけるAI活用の現在 ~モバイルアプリ開発でのAI活用状況と事例~
zozotech
PRO
8
4.1k
AIコーディングエージェント(Gemini)
kondai24
0
150
AIコーディングエージェント(skywork)
kondai24
0
110
ID管理機能開発の裏側 高速にSaaS連携を実現したチームのAI活用編
atzzcokek
0
190
connect-python: convenient protobuf RPC for Python
anuraaga
0
350
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
140
dnx で実行できるコマンド、作ってみました
tomohisa
0
130
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.5k
Making Projects Easy
brettharned
120
6.5k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
8.3k
Producing Creativity
orderedlist
PRO
348
40k
BBQ
matthewcrist
89
9.9k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
Being A Developer After 40
akosma
91
590k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
Git: the NoSQL Database
bkeepers
PRO
432
66k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.8k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
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