3. 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
4. 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
5. 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
6. An API should be testable
In addition to documentation, APIs should have
a site where developers can interactively test
individual API calls
7. 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
10. Why does this matter?
Because we can learn from
what others are doing
11. 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
12. 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
13. Levels of REST
Level Two: is about using HTTP verbs to
define actions on resources
GET https://domain.com/api/v1/profile/uid/1
PUT https://domain.com/api/v1/profile/uid/1
POST https://domain.com/api/v1/profile/uid/1
DELETE https://domain.com/api/v1/profile/uid/1
14. 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”
:…
}
15. 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
16. 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!
21. 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
26. Disclaimer for the last set
of slides
That data dump represents Django views
some of which are not actual API call
27. Some of what follows is
opinionated...
But all of it is up for discussion!
28. 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
29. 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
30. APIs should be versioned
consider:
https://www.bringit.com/api/v1/mission
31. 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
32. 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
33. 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
34. Standardized API names
● Use lowercase: rematch
● Don’t use camel case: wagerAmounts
● Don’t use snake case: inbox_open
Above all - be consistent!
35. 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
36. 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/
and
DELETE https://bringit.com/api/v1/appmessage
* appmessage is the resource and GET and DELETE are actions against the
resource
37. 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
38. 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 workarounds for this:
○ Simply add an HTTP header called X-HTTP-MethodOverride:
■ X-HTTP-Method-Override: PUT
■ X-HTTP-Method-Override: DELETE
○ Google it for more info!
39. 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 groups
Example:
see the members django application
40. 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
41. 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
42. Avoid the use of compound API
names
Example:
● in challenge: wagerAmount
● in user: linkedfriends, invitesent
43. 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
44. 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
45. 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
46. 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
47. 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)
48. 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
49. Topics for future consideration
● API rate metering
● Extended security (OAuth)
50. 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