Curated list of best practices for creating API
Following Apigee api design guide
- There should be only 2 base URLs per resource
- First is for collection, eg.
/dogs
- Second is for element, eg.
/dogs/1234
- First is for collection, eg.
- Keep verbs out of base URLs
- Use HTTP verbs to operate:
post
,get
,put
,delete
for Create, Read, Update, Delete (CRUD) - Example:
/dogs
POST
create new dogGET
get list of dogsPUT
bulk update dogsDELETE
bulk delete all dogs
/dogs/1234
POST
errorGET
get 1 dog 1234PUT
update dog 1234 if existed, else errorDELETE
delete dog 1234
- Use plural nouns, avoid mixed model when using both plural & singular
- Concrete names > abstract name, eg.
/products
,/blogs
are better than/items
,/assets
=> more compelling & useful - Keep the number of resources between 12-24
- Get all dogs belong to owner 5678: don't use
GET /owners/5678/dogs
- Should not need more than this:
/resource/identifier/resource
- Use
?
for URL:GET /dogs?color=red&state=running&location=park
-
Examples:
- Facebook: always get code 200, error code in message, no info about
#803
error or how to reactHTTP Status Code: 200 { "type": "OauthException", "message": "(#803) Some of the aliases you requested do not exist: foo.bar" }
- Twilio: nice to give a link to doc
HTTP Status Code: 401 { "status": "401", "message": "Authenticate", "code": 20003, "more info": "http://www.twilio.com/docs/errors/20003" }
- SimpleGeo: bad -> only error code, no additional info in the message
HTTP Status Code: 401 { "code": 401, "message": "Authentication Required" }
- Facebook: always get code 200, error code in message, no info about
-
Use HTTP status codes
- Use a subset of common codes
- Start from 3:
- All good: Success - 200 OK
- App side: Client error - 400 Bad Request
- API side: Server error - Internal Server Error
- If need more -> add upto 8, try picking from:
- 201 - Created
- 304 - Not Modified
- 404 - Not Found
- 401 - Unauthorized
- 403 - Forbidden
- HTTP Status Codes
-
Make messages verbose, add more hints, use URL for more info
{ "developerMessage" : "Verbose, plain language description of the problem for the app developer with hints about how to fix it.", "userMessage":"Pass this message on to the app user if needed.", "errorCode" : 12345, "more info": "http://dev.teachdogrest.com/errors/12345" }
- Never release an API without a version
- Can use
v3
prefix in URL, don't usev3.1
because it implies that the interface might be changing more frequently than it should - Maintain at least 1 version back, around 6 months to 2 years
- Version in URLs or headers?
- Using headers is more correct
- Leverage existing HTTP standards
- Intellectually consistent with Fielding's vision
- Solve some hard real-world problems related to inter-dependent APIs
- Rules:
- If it changes the logic you write to handle response, need to see easily -> URL
- Else (eg. OAuth information) -> header
- Using headers is more correct
- Partial Response -> give developers just the info they need
/dogs/?fields=name,color,location
- Google:
?fields=title,media:group(media:thumbnail)
-> sub-objexts to pull in other info
- Pagitation
- Facebook, LinkedIn use offset & limit:
?offset=50&limit=25
or?start=50&count=25
-> recommend- More common
- Well understood in leading databases
- Easy for developers
- Twitter uses page & rpp:
?page=3&rpp=25
(rpp
= records per page) - Return metadata: total number of records
- Facebook, LinkedIn use offset & limit:
- Use verbs, nout nouns. Eg.
/convert?from=EUR&to=CNY&amount=100
- Separate these "non-resource" cases in API docs
- Use params like
?alt=json
,?type=json
or/dogs.json
type
param overrides theAccept
header ->Accept: application/json
- Use JSON as default
- Follow JS naming conventions
- Camel Case:
createdAt
instead ofcreated_at
orDateTime
- Use uppercase or lowercase depending on type of object
- Camel Case:
//TODO
- All requests go under one API subdomain ->
api.domain.com
- Do web redirects
//TODO
- Use OAuth 2.0 ->
- Web or mobile apps that expose APIs don't have to share passwords
- Allows the API provider to revoke tokens for an individual user, for an entire app without requiring the user to change their original password
- A virtual layer between the interface on top & API implementation on the bottom
- Create a facade - a comprehensive view of what the API should be, importantly from the API consumer perspective
- API facade isolates the developer/application and the API
-
Use the façade pattern when you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve.
(Gang of Four, Design Patterns - Elements of Reusable Object-Oriented Software) - Implementing -> 3 basic steps:
- Design the ideal API -> design URLs, request params & responses, payloads, headers, query params, etc -> should be self-consistent
- Implement the design with data stubs -> can use API and give feedback even before API is connected to internal systems
- Mediate/ integrate between the facade & the systems