REST API

Table of Contents

Best Practices

URLs and Actions

To prevent an API consumer from having to hit the API again for an updated representation, have the API return the updated (or created) representation as part of the response. In case of a POST that resulted in a creation, use a HTTP 201 status code and include a Location header that points to the URL of the new resource.

GET /tickets
GET /tickets/12
POST /tickets
PUT /tickets/12
PATCH /tickets/12
DELETE /tickets/12
GET /tickets/12/messages
GET /tickets/12/messages/5
POST /tickets/12/messages
PUT /tickets/12/messages/5
PATCH /tickets/12/messages/5
DELETE /tickets/12/messages/5
PUT /gists/:id/star
DELETE /gists/:id/star
GET /tickets?state=open
GET /tickets?sort=-priority
GET /tickets?sort=-priority,created_at
GET /tickets?sort=-updated_at
GET /tickets?state=closed&sort=-updated_at
GET /tickets?q=return&state=open&sort=-priority,created_at
GET /tickets/recently_closed
GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at
Link
Pagination
X-Rate-Limit-Limit
The number of allowed requests in the current period
X-Rate-Limit-Remaining
The number of remaining requests in the current period
X-Rate-Limit-Reset
The number of seconds left in the current period
ETag
Caching
Last-Modified
Caching

JSON

Errors and status codes

{
  "code" : 1234,
  "message" : "Something bad happened :(",
  "description" : "More details about the error here"
}
{
  "code" : 1024,
  "message" : "Validation Failed",
  "errors" : [
    {
      "code" : 5432,
      "field" : "first_name",
      "message" : "First name cannot have fancy characters"
    },
    {
       "code" : 5622,
       "field" : "password",
       "message" : "Password cannot be blank"
    }
  ]
}
200 OK
Response to a successful GET, PUT, PATCH or DELETE. Can also be used for a POST that doesn't result in a creation.
201 Created
Response to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource
204 No Content
Response to a successful request that won't be returning a body (like a DELETE request)
304 Not Modified
Used when HTTP caching headers are in play
400 Bad Request
The request is malformed, such as if the body does not parse
401 Unauthorized
When no or invalid authentication details are provided. Also useful to trigger an auth popup if the API is used from a browser
403 Forbidden
When authentication succeeded but authenticated user doesn't have access to the resource
404 Not Found
When a non-existent resource is requested
405 Method Not Allowed
When an HTTP method is being requested that isn't allowed for the authenticated user
410 Gone
Indicates that the resource at this end point is no longer available. Useful as a blanket response for old API versions
415 Unsupported Media Type
If incorrect content type was provided as part of the request
422 Unprocessable Entity
Used for validation errors
429 Too Many Requests
When a request is rejected due to rate limiting

Versioning

For browser explorability, it is generally better to put the major verion in URI.

I'm a big fan of the approach that Stripe has taken to API versioning - the URL has a major version number (v1), but the API has date based sub-versions which can be chosen using a custom HTTP request header.

Topics

Response of PUT

Updated
200 OK (or 204 No Content), no body needed
Created
201 Created, Location header, URI and metadata as body
Conflict
409 Conflict, list of differences as a body
Failed
400 Bad Request, body contains explanation in a natual language

Visibility

For RESTful web services, your key goal must be to maintain visibility to the extent possible. Keeping visibility is simple. Use each HTTP method such that it has the same semantics as specified by HTTP, and add appropriate headers to describe requests and responses.

Whenever you have multiple resources that share data or whenever an operation modifies more than one resource, be prepared to trade visibility for better abstraction of information, loose coupling, network efficiency, resource granularity, or pure client convenience.

POST vs. PUT vs. PATCH

POST
  • server will decide the URI for the newly created resource.
PUT
  • client is determining the URI for the newly created resource.
  • The PUT method requests that the enclosed entity be stored under the supplied Request-URI.
PATCH
  • when the client is sending one or more changes to be applied by the server.
  • applies a delta rather than replacing the entire resource.

Is it okay to return JSON Array

[1, 2, 3]
{
  "meaningless_key": [1, 2, 3]
}
Pros
can extend the result, like including count.
Cons
less pretty

Overall: It is better to use enveloping arrays with objects.

Principles

Stateless
induces the properties of visibility, reliability, and scalability.
Cache
improves network efficiency
Uniform Interface
overall system architecture is simplified and the visibility of interactions is improved.
Layered System
improves behavior for Internet-scale requirements, we add layered system constraints
Code-On-Demand
allows client functionality to be extended by downloading and executing code in the form of applets or scripts.

Request (a)
a client proxy scenario
Request (b)
a direct request scenario
Request (c)
a server proxy scenario