api presentation

50
featuring the BringIt API A look at API design [email protected]

Upload: carlos-justiniano

Post on 22-Nov-2014

400 views

Category:

Technology


0 download

DESCRIPTION

A look at API design considerations

TRANSCRIPT

Page 1: API presentation

featuring the BringIt API

A look at API design

[email protected]

Page 2: API presentation

API Design Goals

Page 3: API presentation

Good APIs are designed with end users in mind

● Ease of use is important!● The API should be clear and consistent

● If you had to guess where you might find a particular piece of functionality you should be able to guess correctly or be fairly close!

● Design against standards and don’t invent your own○ Do this for the same reasons we all agree to use frameworks.

● Good documentation is vital

Page 4: API presentation

What should an API do?

● be easy to learn and use● should be difficult to misuse● should be easy to evolve over time● should do one thing and do it well● should be easy to explain - if not, perhaps it’

s not doing one thing well?● lend itself to reuse to avoid having other

programmers warp the API to deal with it in a sane way

Page 5: API presentation

An API should be testable

APIs should be testable (yes, I repeated that)

By testable I mean that one should be able to write integration tests which demonstrate working API calls

In contrast, unit test should be mocked

Page 6: API presentation

An API should be testable

In addition to documentation, APIs should have a site where developers can interactively test individual API calls

Page 7: API presentation

API Red Flags

● It’s a red flag when you can’t find what you’re looking for in an API

● … and when you can’t come up with a good name for the API call

● Good API names are vital!

“The names are the API talking back to you - so listen to them.” - Joshua Bloch, Google Talks, Jan 2007

Page 8: API presentation

APIs in the wild

Page 9: API presentation

Lots of companies have APIs...

● https://dev.twitter.com/docs/api/1.1● http://www.wunderground.com/weather/api/● http://developer.yahoo.com/boss/● https://developers.google.

com/maps/documentation/javascript/3.exp/reference

● https://www.dropbox.com/developers/core/docs

● http://dashboard.swrve.com/help/docs

Page 10: API presentation

Because we can learn from what others are doing

Why does this matter?

Page 11: API presentation

Almost all APIs in the wild follow an architectural approach, called REST

● REST, stands for REpresentational State Transfer. REST isn’t a standard, but rather an architectural approach / recommendation

● Most APIs claiming to be REST don’t fully implement REST concepts

● There are three widely accepted levels of REST, most APIs implement most of the first level, some implement parts of the second level, and only few implement the third level of the recommendations

Page 12: API presentation

Levels of REST

Leonard Richardson described these three levels of REST which is known today as the Richardson Maturity Model

Level One: is all about treating URIs as resources.

https://domain.com/api/v1/profile/uid/1

returns a profile with a UID of 1

Page 13: API presentation

Levels of REST

Level Two: is about using HTTP verbs to define actions on resources

GET https://domain.com/api/v1/profile/uid/1PUT https://domain.com/api/v1/profile/uid/1POST https://domain.com/api/v1/profile/uid/1DELETE https://domain.com/api/v1/profile/uid/1

Page 14: API presentation

Levels of REST

Level Three: is about using hyperlinks in the data returned to allow for the navigation of URIs

Example:{ “href”: “https://site.com/api/v1/profile/uid/1”

: …}

Page 15: API presentation

REST usage

As mentioned earlier, most APIs don’t fully implement REST● Most expose resources - so level one

support is almost a given● For level two, most only support HTTP

GET/POST - many lack support for PUT and DELETE

● Level three support for Hyperlinks is unsupported by most APIs

Page 16: API presentation

REST vs. RESTful

So lack of full REST support (buy in) results in varied support of REST. We say that an API is RESTful if it attempts to follow REST guidelines, namely level one and two on the Richardson Maturity (scale) Model

It turns out that even limited REST support can lead to some consensus regarding API construction. This is a GOOD thing!

Page 17: API presentation

To REST or not to REST?

Page 18: API presentation

When it comes to API design you can follow a

standard - or do your own thing...

Page 19: API presentation

… then explain later what the $%^& you were

thinking

Page 20: API presentation

BringIt APICleanup opportunities

Page 21: API presentation

Good News!As I reviewed the BringIt API I realized it’s actually in pretty good shape - for a first pass!

With some improvements we’ll have a version 2 API that will be easier to use and model what others are doing

This will make it more easily accepted by external developers who already have experience with industry APIs

Page 22: API presentation

BringIt APIappmessages/

sandbox

u/read/

u/delete/

b/read/

b/read/(?P<message_id>\w+)/

activityfeed

activityfeed/(?P<context>\w+)/

activityfeed/(?P<context>\w+)/(?P<game_id>\d+)/

flush_notification_queue/(?P<uid>\d+)/

gen_notification_queue/(?P<uid>\d+)/

inbox_open/

authenticate/ authenticate.urls

iframe/(?P<partner_id>\d+)/

registerguest/

registeruser/

auth/

partner_auth/

challenge

game/(?P<game_id>\d+)/

(?P<chal_id>\w+)/join/

(?P<chal_id>\w+)/standings/

(?P<chal_id>\w+)/payout/

(?P<chal_id>\w+)/rank/

create/

wagerAmount/

payout/(?P<game_id>\d+)/

wagerAmounts/

create/(?P<game_id>\d+)/(?P<wager_amount>\d+)/(?P<challengee_id>\d+)/

status/(?P<challenge_id>\w+)/(?P<action>\w+)/

rematch/(?P<challenge_id>\w+)/

remind/(?P<challenge_id>\w+)/

history/

contact

/

email contact?

Page 23: API presentation

BringIt APIems

not an API?

fbhost

landing/

iframe/

connect/

site/

payments/

channel/

currency_object/(?P<partner_id>\d+)/

fbproduct/(?P<partner_id>\d+)/(?P<category>currency|tournament|missiontask)/(?P<item_id>[a-zA-Z_0-9-.]+)/

fbfulfillment/

likecount/

fbsocial

/

gifttest/

login/

test/

noauth/

requesttagger/

Should be combined into facebook

gamesession

startgame/(?P<game_id>\d+)/

reportscore/

gameupdate/

gameroom

/

gifting

currently in member.urls

gifting/

giftsend/

giftredeem/(?P<gift_request_id>\d+)/(?P<to_id>\d+)/(?P<from_id>\d+)/

gifter_rewards/

h2h/ challenge.urls

inventory/ inventory.urls

/

Page 24: API presentation

BringIt APIactive/

activate/(?P<inventory_id>\w+)/

(?P<game_id>\d+)/

redeem/(?P<game_id>\d+)/(?P<item_type>\w+)/

leaderboard/ leaderboard.urls

update/

dev_reset_global/(?P<game_id>\d+)/

dev_reset_friends/(?P<game_id>\d+)/(?P<user_id>\d+)/

missions/ missions.urls

skip/

tasklist/

taskpaytocomplete/(?P<task_id>\w+)/

missionpaytounlockslot/

dev_taskcomplete/(?P<task_id>\w+)/

dev_generatemissioncompletedmessage/(?P<mission_id>\w+)/

dev_generatetaskcompletedmessage/(?P<task_id>\w+)/

dev_resetmission/(?P<mission_id>\w+)/

dev_resetallmissions/

dev_resetallandgrantmission/(?P<mission_id>\d+)/

recommend/ member.urls

solo/ challenge.urls

store/ store.urls

/

(?P<game_id>\d+)/

purchase/(?P<inventory_id>\w+)/

earn/(?P<inventory_id>\d+)/

purchase/(?P<game_id>\d+)/(?P<item_type>\w+)

purchase/(?P<game_id>\d+)/(?P<item_type>\w+)/(?P<quantity>\d+)/

earn/(?P<game_id>\d+)/(?P<item_type>\w+)

currency_paytables/

swrve/ swrve.urls

tournaments/ challenge.urls

user/ member.urls

/

is_new_user/

(?P<user_id>\d+)/$

game/(?P<game_id>\d+)/

Page 25: API presentation

BringIt API linkedfriends/

badges/

goals/

balance/

sent/

gifting/

giftsend/

giftredeem/(?P<gift_request_id>\d+)/(?P<to_id>\d+)/(?P<from_id>\d+)/

gifter_rewards/

invite/

invitesent/(?P<app_request>\d+)/

redeemcount/

dev_setredeemcount/(?P<count>\d+)/

fb_notification/

arcadeinvite/recommend/

arcadeinvite/(?P<action>accept|decline|drop)/reply/(?P<sender_id>\d+)/

arcadeinvite/

xp_info/

dev_setxp/(?P<xp_value>\d+)/

fb_share/(?P<share_type>\w+)/

fb_share_event/

fb_share_ibm/

fb_like/

dev_fb_unlike/

dev_set_first_time_user/

tutorial/(?P<tutorial_name>\w+)/step/(?P<step>\w+)/

daily_bonus_prize/

ping/

heartbeat/ member.urls

Page 26: API presentation

That data dump represents Django views some of which are not actual API call

Disclaimer for the last set of slides

Page 27: API presentation

But all of it is up for discussion!

Some of what follows is opinionated...

Page 28: API presentation

API Path should be separate

This would provide a logical place to look when trying to understand the API layout

Would allow for a separation between views and API. It might be desirable to have view handlers which are not considered public API

Page 29: API presentation

API Path should be separate

The API shouldn’t necessarily have a direct 1-1 relationship to a specific data model

Examples: https://bringit.com/api/member

https://api.bringit.com/member

Page 30: API presentation

APIs should be versioned

consider: https://www.bringit.com/api/v1/mission

Page 31: API presentation

Module names could be singular rather than plural

Examples:● appmessage instead of appmessages

○ or better yet: /mesage● mission instead of missions● tournament instead of tournaments

Page 32: API presentation

Avoid using abbreviations in URIs

Abbreviations introduce conceptual overhead, which doesn’t help when trying to keep things simple and clear

Examples:● appmessages: u/read, u/delete, b/read

Page 33: API presentation

Names used in API should be lowercase

Currently mixed case is used which leads a developer to wonder where mixed case is used and where it is not

Page 34: API presentation

Standardized API names

● Use lowercase: rematch● Don’t use camel case: wagerAmounts● Don’t use snake case: inbox_open

Above all - be consistent!

Page 35: API presentation

Consider using actual HTTP returns values

In our API we almost always return HTTP 200 when we should consider returning HTTP 201 and other values such as 40x and 50x

The idea is that an HTTP client should be able to correctly process HTTP messages without having to examine the JSON payload

Page 36: API presentation

Use HTTP action verbs to minimize API bloat

In appmessages we have u/read and u/delete

Using HTTP action verbs we would have:

GET https://bringit.com/api/v1/appmessage/andDELETE https://bringit.com/api/v1/appmessage

* appmessage is the resource and GET and DELETE are actions against the resource

Page 37: API presentation

Use HTTP action verbs to minimize API bloat

HTTP PUT can be used to queue messages and HTTP POST can be used to update existing messages

This saves us from potentially creating API such as:● appmessage/readmessage● appmessage/deletemessage● appmessage/addmessage● appmessage/updatemessage

Page 38: API presentation

Use HTTP action verbs to minimize API bloat

● One of the biggest reasons why developers don’t use PUT and DELETE is because it’s not supported by older web browsers

● Few developers know that there are work-arounds for this:○ Simply add an HTTP header called X-HTTP-Method-

Override:■ X-HTTP-Method-Override: PUT■ X-HTTP-Method-Override: DELETE

○ Google it for more info!

Page 39: API presentation

API should be grouped by resource type

When deciding how an API call should be grouped ask the question:

What type of resource is this?

Don’t overload groupsExample:

see the members django application

Page 40: API presentation

API should be grouped by resource type

gifting, invite, challenge, facebook, should all be in their own group

Examples: fbshare should be /facebook/share and should probably not be found under the member group

Same applies to lots of the API found in the member

Page 41: API presentation

Resource types should not be described by multiple names

User and Member are confusing

If goal is to avoid confusion with Django user then member should be used exclusively

Page 42: API presentation

Avoid the use of compound API names

Example:● in challenge: wagerAmount● in user: linkedfriends, invitesent

Page 43: API presentation

Avoid having both single and plural versions of an API name

Examples:● wagerAmount and wagerAmounts

A single resource “wager” should return a single wager when and id is provided and a list of wagers when an id is not provided

Page 44: API presentation

Avoid use of action words in API

Example:● In challenge the word create is used for

solo_create and h2h_create only parameters differ

When possible use HTTP VERBS to specify actions

Page 45: API presentation

APIs should have a private and public face

Private APIs (those starting with dev_) should be controlled by policies on the web server

This allows for private APIs to be called from known IPs / gateways and blocked from public use

Page 46: API presentation

Rename dev_ API calls

Private APIs are still API calls like any other. In fact, many APIs might be used internally between distributed infrasture components and not exposed for general or external use

Visibility should be controlled by web server policies

Page 47: API presentation

Bandwidth optimizations

Consider using ?_body=false to tell the server that you don’t care about a returned response body and that you’ll instead look at the HTTP return code only

Add support for selective field retrieval using sets, example:https://domain.com/api/v1/user?fields=(UID,firstName,lastName)

Page 48: API presentation

Bandwidth optimizations

Consider returning results in batches, ala paging

So return first 20 items then allow client to request next 20 items etc… Also allow client to specify how many items it would like to receive

This allows for overriding small batches if necessary

Page 49: API presentation

Topics for future consideration

● API rate metering● Extended security (OAuth)

Page 50: API presentation

Closing thoughts

Today APIs are in widespread use

We don't need to look far for examples of clean APIs

Many packages exist for your programming language of choice which help simplify using RESTful services