Six best practices when building REST APIs

When building modern web applications, a common practice is to have a front-end server act as a REST API. This server generally exposes certain endpoints. It accepts HTTP requests and returns JSON responses. The JSON is then consumed by a client-side JavaScript framework, which uses it to display information to the user.

Today, we’re going to talk about building RESTful APIs and some best practices that I have learned by making mistakes over the years. Most of these are pretty simple but often overlooked.

1. Separate your Response into meta and data fields

When sending a JSON response, it is useful to separate meta information (information about the request/response), from the payload that you are sending back.

// GET /api/users/1

{
    "meta": {
        "type": "success",
        "code": 200,
        "message": "",
        "responseId": "43qtf3hk03y34gm41"
    },

    "data": {
        "id": 1,
        "name": "Joe Burns"
    }
}

By adopting this pattern, your API consumers will be able to provide better error messages to the end user. I’ve also been playing around with providing a unique responseId for all my responses using the uuid module in Node. By combining this with HTTP access logs, I’m able to quickly debug problems in my API.

Note: I’ve been helpfully reminded on Reddit that you can alternatively use HTTP Response headers to store this meta information. That’s probably more “pure”, but I suggest choosing one convention and sticking to it.

2. Use plural names for all resources. Don’t use verbs

Give your resources plural names so that it makes more sense when querying. Here’s an example to demonstrate the point.

// Good
/api/customers: Fetch all customers
/api/customers/25: Fetch customer with ID: 25

// Bad
/api/customer: Fetch all customers, but no plural.
/api/customer/25: Fetch customer with ID: 25

// Bad (don't use verbs)
/api/getcustomers
/api/getcustomers/25

3. Use proper HTTP Status Codes

Don’t always return a 200 status. Here’s a handy list showing what HTTP status codes to return with:

  • 200 Ok: Use this if everything worked well.
  • 201 Created: Use this for POST requests when you create a new resource. This is better than the generic 200.
  • 204 No Content: Use this when you have successfully deleted a resource.
  • 400 Invalid Request: Use this if all the parameters were not provided.
  • 401 Unauthorized: Use this if you had a permissions issue.
  • 403 Forbidden: Use this if you had a permissions issue.
  • 404 Not Found: Use this if you were not able to find the resource.
  • 500 Internal Server Error: Use this if your server encountered an error. If you do return with a 500, make sure you return a human-readable message that your API consumer can use.

I normally add the status code to the meta object as well.

4. Use proper RESTful Methods

  • Use GET for retrieving resources.
  • Use POST for creating new resources.
  • Use PATCH for updating resources.
  • Use DELETE for deleting resources.

This makes it simpler to define the API. You won’t need to do something like this:

//BAD

/api/getCustomers
/api/getCustomers/:id
/api/updateCustomer/:id
/api/deleteCustomer/:id

// Good

GET /api/customers
POST /api/customers
PATCH /api/customers/:id
DELETE /api/customers/:id

5. Version your API

This isn’t necessary if you are building internal APIs, but it is a must if you want to expose your API to consumers outside your company.

/api/v1/customers/:id

// If you make non-backward compatible changes to this
// endpoint, don't change v1. Just create a new endpoint.

/api/v2/customers/:id

Users expect their APIs to be predictable, and by versioning them, you can make changes while ensuring older versions are backward-compatible.

6. Use query strings to manipulate data

Query strings should be used for sorting, searching and filtering data. You can also use it to add pagination via limit and offset query strings. Filtering should generally be done by the attribute name of the resource.

// Get all customers.
/api/v1/customers

// Get all customers sorted by name in ascending order.
/api/v1/customers?sort=name&direction=asc

// Get all customers whose first name is Jack.
/api/v1/customers?name=Jack

// Get first 30 customers sorted by name.
/api/v1/customers?sort=name&direction=asc&limit=30

// Get 31-60 customers sorted by name
/api/v1/customers?sort=name&direction=asc&limit=30&offset=30

The examples above obviously aren’t the only way to use query strings. You can create your own conventions.

Comments are closed.

Up Next:

How to build and deploy static websites using Metalsmith

How to build and deploy static websites using Metalsmith