The API Design Guide

notes 10 min #API

contents

An API allows one piece of software talking to another piece of software

Definitions

Some terms used in this guide and there definitions:

AIM

The aim of this design guide is to assist in the planing and development of a REST API.

Overview

An API is an: Application Programming Interface. An interface for one piece of software to talk to another[^concepts] and data to be shared. It is a set of endpoints for serving up data.

REST API

REST API is an architectural design style that follows a defined set of objectives. It was first defined by Roy Thomas Fielding in his 2000 PhD dissertation “Architectural Styles and the Design of Network-based Software Architectures”.

The REST architectural style aims to be:

Success

A successful REST API, is one that:

Documentation

The API should be well documented with cURL examples with JSON responses. A cURL examples can be cut-and-pasted, removing any ambiguity regarding endpoint calls and applicable JSON responses.

API BASE/ROOT URL

The root or entry point into the API should be as simple as possible. Long complex URLs appear daunting. Two common API roots are:

  1. https://api.example.com/*
  2. https://example.com/api/*

The single root entry point should contain some basic information about the API, such as:

Versioning

The version number should refer to major releases of the API. An API is never going to be stable, change is inevitable in fact needed. What is important is how that change is managed. When third-party software applications (clients) integrate with your API, they become dependent on the availability of the API. Versioning allows for backwards compatibility and continued development.

There are two common methods for managing API versions:

  1. in the request HTTP header;
Accept: application/com.ianteda.app-v3+json
Content-Type: application/com.ianteda.app-v3+json 
  1. in the URL;
GET https://api.example.com/v1/endpoint

This guide recommends option 2. Having the API version in the endpoint URL, it is obvious and human readable.

Security

All API requests and responses should be over SSL (HTTPS). Do not redirect non-SSL requests to the SSL endpoint, as this can leak information. Instead throw an API error response when the request comes over non-SSL.

With the use of Webtokens, SSL simplifies the authentication model. Never use a custom authentication protocol, stick to the standards like Oauth 2. Webtokens means the users state (authentication) is kept on the user end, sot that every request can be authenticated against the webtokens. This avoids server session states, sticking to the REST stateless server principle.

Access within the API should be based on the resource not the endpoint URL.

Use request rate limiting to the endpoints, to avoid performance issues.

Keep in mind when providing authentication responses that:

Error Messages

When responding with an error the JSON body should return a useful error message, a unique internal error code with reference to documentation, a detailed description and a 400 http status. Error messages should be human-readable from the browser, include a diagnostic message to help the consumer resolve the error condition and be as descriptive as possible.

Status: 400 BAD REQUEST
{
  "code" : unique_project_code,
  "property" : "What caused the error",
  "message" : "Something bad has happened :(",
  "description" : "More details about the error here",
  "developer_message : "Extra information to help resolve the error response",
  "documentation_url": "https://ianteda.com/api/documentation"
}

Endpoints

Rules

Some Endpoint rules to keep in mind:

Actions

Typical actions on an endpoint

MethodURI end pointNotesGET/resourceReturns a list of all the resources in the collection. By default items in the list are a minimal representation of themselvesGET/resource/{key}Returns the full content of the resource identified by the given key (name or id)POST/resourceCreate a new resourcePUT/resource/{key}Update a resource identified by the given key (name or id)PATCH/resource/{key}Partially update a resource identified by the given key (name or id)DELTE/resource/{key}Delete a resource identified by the given key (name or id)

Relationships

One to many relationships

If Relationships exist within a resource, extend the endpoint.

MethodURI end pointNotesGET/resource/{key}/relationshipRetrieve a list of relationships for the resource {key (name or id)}GET/resource/{key}/relationship/{key}Retrieve relationship {key} (name or id) for a given resource {key (name or id)}POST/resource/{key}/relationshipCreate a new relationship for a given resource {key (name or id)}PUT/resource/{key}/relationship/{key}Update relationship {key} (name or ide) for ticket {key (name or id)}PATCH/resource/{key}/relationship/{key}Partially update relationship {key (name or id)} for resource {key (name or id)}DELETE/resource/{key}/relationship/{key}Delete relationship {key (name or id)} for resource {key (name or id)}

Many to many relationships

If the relationship exists external to a resource, provide an end point for the relationship. With a href link within the resource response to the relationship. By creating an endpoint for the relationship it can be deleted without deleting the resource.

Provide Request-Ids for Introspection

Include a Request-Id header in each API response, populated with a UUID value. By logging these values on the client, server and any backing services, it provides a mechanism to trace, diagnose and debug requests.

Pagination

Divide large responses across multiple requests with pagination. Using offset and limit parameters

Provide links within the paged response to other pages.

{
  "first" : "/resource/00001",
  "previous" : "/resource/34523",
  "next" : "/resource/34525",
  "last" : "/resource/8764534",
  "index : {
    00001: "/resource?offset=0&limit=25",
    00002: "/resource?offset=25&limit=25",
    00003: "/resource?offset=50&limit=25"
  }
}

Parameters

Complex result filters, sorting and searching can all be easily implemented as query parameters on top of the resource URL

Filtering

Use a unique query parameter for each field that implements filtering. When requesting a list of resources from the /resources endpoint the default should be the smallest practical, say those in the open state. Provide a mechanism to return all GET /resources?state=all or those closed GET /resources?state=closed

Sorting

Use the a generic parameter such as ?sort= to describe sorting rules for a resource endpoint. Accommodate complex sorting requirements with a list of comma separated fields, each with a possible unary negative for descending order or positive.

Searching

Sometimes basic filters is not enough and you need the power of full text search. Use a query parameter on the resources endpoint ?query=search term. Search queries should be passed straight to the search engine and API output should be in the same format as a normal list result.

To make the API experience more pleasant for the average consumer, consider packaging up sets of query conditions into easily accessible endpoints.

HTTP status codes

HTTP status codes can help your consumers navigate your API. Providing context to the API responses.

Useful list of API HTTP status codes

CodeStatusNotes200OKResponse to a successful GET, PUT, PATCH or DELETE. Can also be used for a POST that doesn’t result in a creation201CreatedResponse to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource204No ContentResponse to a successful request that won’t be returning a body (like a DELETE request)304Not ModifiedUsed when HTTP caching headers are in play400Bad RequestThe request is malformed, such as if the body does not parse401UnauthorizedWhen no or invalid authentication details are provided. Also useful to trigger an auth popup if the API is used from a browser403ForbiddenWhen authentication succeeded but authenticated user doesn’t have access to the resource404Not FoundWhen a non-existent resource is requested405Method Not AllowedWhen an HTTP method is being requested that isn’t allowed for the authenticated user410GoneIndicates that the resource at this end point is no longer available. Useful as a blanket response for old API versions415Unsupported Media TypeIf incorrect content type was provided as part of the request422Unprocessable EntityUsed for validation errors429Too Many RequestsWhen a request is rejected due to rate limiting

References