Designing a REST API

This is meant to be an ongoing post updated as I make my mind on different issues about API design.

REST CRUD
POST CREATE
GET READ
PUT UPDATE
DELETE DELETE

Authentication

  • OAUTH 2.0
  • Access token delivered in HTTP Basic Auth username field is also a good method to transfer access credentials.
  • For JSONP ?access_token query parameter can be used, but it is a security risk because access credentials will be saved in web server logs
  • In any case, HTTPS must be the only way to access the API and under no circumstances plain text data communication should be allowed.

Resources

  • Verbs are bad
  • Nouns are good, use plural nouns as resources
  • The only verbs used are post, get, put and delete
  • Anything more complex put after the ?
    /dogs?color=black&state=running&location=earth
Example POST GET PUT DELETE
dogs create new dog list dogs bulk update dogs delete dogs
dogs/1234 error get dog id 1234 update dog 1234 delete 1234
owners/321/dogs create dog for owner gets dogs of owner update dogs of owner delete dogs of owner
owners/321/dogs/1234 error get dog 1234 of owner 321 update dog 1234 of owner 321 delete dog 1234 of owner 321

Format

  • JSON only
    I never liked XML, never was very good at it. So although I am usually tempted to add a format option to the api and generate output in JSON and XML, I am going to skip XML from now on and use JSON as the default and only format.
  • Pretty json output and gzip compression by default.
  • No envelope for returned attributes by default. If envelope is needed api specifications can provide an ?envelope=true option in which case meta and response attributes can be returned in an envelope.
  • Although a lot of smart people say camelCase I think snake_case makes for better readability.

Versioning

  • Mandatory Versioning
  • Versions in URL api.example.com/v1/dogs
  • If needed subversions can be provided in the header

Return Codes

  • Return correct HTTP status codes.
    200 – OK
    201 – Resource Created
    401 – Unauthorized
  • Optionally provide additional internal status codes and links to documentation / discussion pages.
{
"status": 401,
"message": "Unauthorized",
"code": 20003,
"more_info": "http://location/docs/errors/20003"
}
  • Optionally allow ?suppress_http_status_codes_and_use_envelope=true to suppress HTTP status codes and always return 200 – OK with additional status information. We use envelope here to prevent collision of status and error information with other attributes.

Filtering, Sorting, Searching

  • /dogs?color=black – Return only black dogs
  • /dogs?color=black&sort=-age – Return only black dogs and sort by age in descending order
  • /owners/123/dogs?color=black – Return only black dogs of owner 123
  • /dogs?q=rocky – If available, full text search
  • /search?q=rocky – Global search across resources, use search as a reserved word

Pagination

  • /dogs?limit=25&offset=50
    In my opinion, limit and offset should be the preferable choice here, mostly because most open source databases support limit and offset for queries.
  • /dogs?count=25&start=50
    For some reason I have a problem understanding limit and offset. I have to mentally stop and think for a second to understand what it means. So I would like limit/count and offset/start to be used interchangeably.
  • X-Total-Count HTTP header for the total count.
  • Should already have a reasonable default. (i.e. limit=10, offset=0)

Partial Response

All of the resource attributes are not always needed and giving the client ability to ask for a subset of the fields is good design.

  • /dogs?fields=name,color,location
  • /owners?fields=name,dogs(name)

Other Considerations / Not Decided

  • Caching
  • Binary Data
  • Links
  • HATEOAS
  • Rate Limiting

Design Tools

  • I have decided on using RAML for API design and documentation. I looked at a lot of different things (Swagger, API Blueprint, XML, etc.) To be honest API Blueprint seems very mature and I like Markdown but still my decision was towards RAML. So that’s that.

References

Leave a comment