Slide 1

Slide 1 text

MOVE FAST, DON'T BREAK YOUR API AMBER FENG @amfeng

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

LET'S BUILD AN API!

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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 }

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

WHAT NEXT?

Slide 10

Slide 10 text

WHAT NEXT? MORE ENDPOINTS

Slide 11

Slide 11 text

WHAT NEXT? MORE ENDPOINTS MORE FUNCTIONALITY

Slide 12

Slide 12 text

WHAT NEXT? MORE ENDPOINTS MORE FUNCTIONALITY MORE CHANGES

Slide 13

Slide 13 text

WHAT NEXT? MORE ENDPOINTS MORE FUNCTIONALITY MORE CHANGES MORE PROBLEMS

Slide 14

Slide 14 text

LARGE, TANGLED CODEBASE

Slide 15

Slide 15 text

COPY-PASTA

Slide 16

Slide 16 text

ERROR-PRONE DEPENDENCIES

Slide 17

Slide 17 text

"CRAP, I FORGOT TO UPDATE THE DOCS!" — Everyone ever

Slide 18

Slide 18 text

HOW DO WE MAKE IT BETTER?

Slide 19

Slide 19 text

DESIGN FOR YOURSELF, TOO

Slide 20

Slide 20 text

SEPARATE DIFFERENT LAYERS OF LOGIC

Slide 21

Slide 21 text

Authentication Validation Endpoint-specific logic Constructing the response Error handling

Slide 22

Slide 22 text

Error handler Authenticator API logic

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

APIMethods & APIResources

Slide 25

Slide 25 text

class ChargeCreateMethod < AbstractAPIMethod required :amount, :integer required :card_number, :string resource ChargeAPIResource def execute create_charge(amount, card_number) end end

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

post '/v1/charges' do APIMethod::ChargeCreateMethod.invoke end get '/v1/charges' do APIMethod::ChargeRetrieveMethod.invoke end

Slide 28

Slide 28 text

MAKE IT HARD TO MESS UP

Slide 29

Slide 29 text

class ChargeCreateMethod < AbstractAPIMethod required :amount, :integer required :card_number, :string document :amount, "Amount, in cents." document :card_number, "The card number." ... end

Slide 30

Slide 30 text

HIDE BACKWARDS COMPATIBILITY

Slide 31

Slide 31 text

Slide 32

Slide 32 text

def execute if !user.version_1? && params[:amount] raise UserError.new("Invalid param.") end ... if !user.version_1? response.delete(:amount) end end

Slide 33

Slide 33 text

GATES

Slide 34

Slide 34 text

- :version: 2014-09-24 :new_gates: - :gate: allows_amount :description: >- Sending amount is now deprecated.

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

COMPATIBILITY LAYERS

Slide 37

Slide 37 text

Request compatibility API logic Construct API response Response compatibility

Slide 38

Slide 38 text

IN THE REAL WORLD

Slide 39

Slide 39 text

106 ENDPOINTS 65 VERSIONS 6 API CLIENTS

Slide 40

Slide 40 text

DESIGN FOR YOURSELF: SEPARATE LAYERS OF LOGIC MAKE IT HARD TO MESS UP HIDE BACKWARDS COMPAT

Slide 41

Slide 41 text

WHAT ELSE?

Slide 42

Slide 42 text

NOT SURE. (WE'RE STILL FIGURING IT OUT AS WE GO.)

Slide 43

Slide 43 text

THANKS! (: @amfeng