RESTful API Design Guidelines
This document covers the guidelines for the designing RESTful style APIs. It represents best practices gleaned from studying industry standard APIs. The intended audience of this document is someone planning on exposing an existing service or a newly implemented service via RESTful API.
This document references the following subject areas that will be involved in implementing a RESTful API.
HTTP Methods
Media Types
URI Templates
Resource Modelling
Data Representation
HTTP Methods
Advantages of uniform interfaces are familiarity, interoperability, and scalability.
GET – Retrieve a resource
It is used to query the server.
It is both an idempotent and safe operation. There should not be any side-effects, other than possible meta-data (e.g. last accessed timestamp)
The idempotent property enables various caching strategies to be leveraged by browsers and proxy servers.
PUT – Update a resource.
Updates the representation of an entity. The updated representation is passed in the message body.
The semantic of PUT is modeled as an insert or update.
It is also idempotent.
DELETE – Delete a resource
It removes a given resource.
It is also idempotent.
POST – Create a new resource
Creates a new entity.
Post is both a non-idempotent and an unsafe operation.
HEAD
This is similar to GET except it returns a response code only. This is generally not needed for standard REST calls.
OPTIONS
This allows the requester to retrieve the capabilities of a server without any effect on a resource. This is generally not needed for standard REST calls except for implementing preflight requests.
Safety and Idempotency
Method | Safe (no side effects) | Idempotent (request can be repeated) | Description |
|---|---|---|---|
GET | Yes | Yes | Read a resource |
PUT | No | Yes | Update a resource |
DELETE | No | Yes | Delete a resource |
POST | No | No | Create a resource |
Specific Items and Collections
Method | Specific Item | Entire Collection |
|---|---|---|
GET | 200 (OK), 404 (Not Found) | 200 (OK) |
PUT | 200 (OK), 204 (No Content), 404 (Not Found) | 404 (Not Found) – not desirable to update every resource in a collection |
DELETE | 200 (Ok), 404 (Not Found) | 404 (Not Found) – not desirable to delete an entire collection. |
POST * | 404 (Not Found) – should use PUT to update an item. | 201 (Created) |
Note: sometimes POST is used as a catch-call for special cases that defy standard use cases
Other Special Cases
POST for long-running requests. Use a “Job” or “Task” to wrap response
POST for sensitive data – To ensure that sensitive data (e.g., credentials) is encrypted via https, always use POST so that the sensitive data is in the payload and not in the URL.
POST for complicated queries – POST can be used when it would be too cumbersome to use query parameters with GET. For example, supposing the use-case is to search for several customers simultaneously and each customer is represented as First Name, Last Name and ZIP code. Then, the input is an array of objects, which is cumbersome to represent in a flattened way, as you would with query parameters.
Status Codes
Use HTTP status codes and try to map them cleanly to relevant standard-based codes. Minimally, use the following 10 codes.
200 – OK
201 - Created – always use this for POST
304 - Not Modified
400 - Bad Request
401 – Unauthorized
403 – Forbidden
404 - Not Found
406 - Not Acceptable
415 - Unsupported Media Type
500 - Internal Server Error (Normally this is generated by the server and not the application code). Never expose stack exceptions in a response.
Media Types
Interaction with a service takes place using resource representations of that service. From the client point of view, the Content-Type header specifies data format of the representation for describing input, while the Accept header specifies data format of the representation for describing output. The client and server can negotiate the representation format using these headers to indicate a media type (also known as MIME).
The most commonly used media type is application/json.
Others media types used are:
application/x-www-form-urlencoded (for PUT and POST only)
application/xml or text/xml
application/javascript
text/plain
text/csv (facilitates “export” capability)
Content-Type Header
To describe the request input payload format and/or response payload output, use the Content-Type header.
Minimally, support these media types using these headers:
application/json
application/x-www-form-urlencoded
If a request call includes a Content-Type header that indicates an unsupported media type, a 415 Unsupported Media Type error should be returned.
Accept Header
To request (content negotiation) a specific response format (other than the default), use the Accept header
application/json
If a request call includes an Accept header that indicates an unsupported media type, a 406 Not Acceptable error should be returned.
URI Templates
Uniform Resource Identifier (URI) is used to identify a resource. https://tools.ietf.org/html/rfc6570
A URI Template is a compact sequence of characters for describing a range of Uniform Resource Identifiers through variable expansion. This specification defines the URI Template syntax and the process for expanding a URI Template into a URI reference, along with guidelines for the use of URI Templates. URI is standardized as follows:
URI = scheme “:” authority “/” path [ “?” query ] [ “#” fragment ]
Scheme – is the communication protocol and is one of: http | https. However we only use https for better security.
Authority is the host and port and represents the base location of a given resource.
Path is a set of text strings delimited by “/”
Query string is list of parameters specified as name=value pairs. Each pair is delimited by the “&” character.
Fragment is delimited by “#” and fragment points to a specific location within the document.
NOTE: the following examples are for the front-end façade URIs. The exact base path for the front-end URI is determined as a part of the API Publishing task. Front-end URIs can map to any backend URIs up to the point of the first resource.
Backend URIs that talk directly to a given service provider's (you), service should follow a similar pattern.
URI = scheme “:” authority “/” path [ “?” query ] [ “#” fragment ]
For the internal services that are developed for NEXEN Access Cloud, the following is the suggested URI pattern:
Scheme = https
Authority
Production: apigateway.example.com
Path = /<apiName>/<version>/<resource>
Resource Modeling
“The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.” - Roy Fielding’s dissertation.
Resources can be:
Collections, for example /customers
A single entity within a collection, also known as a document, for example "/customers/C12345"
A resource may contain sub-collection resources. This is desirable to minimize the number of API calls needed to perform a task and thus reduce “chattiness”. On the other hand, embedding too many sub-collections in a response may make the response payload large and unwieldy. The right balance needs to be considered. One possible solution to this is to include a query parameter to indicate whether or not the sub-collection should be expanded in the response payload. For example ?expand=true.
Sometimes there will be functionality in the service that defies being factored into resources. This is sometimes true of actions, for example, calculate, translate, convert, etc. For this situation, verbs are used, but they are a rare exception.
Resource Naming
Resource names should be simple, single-word nouns that are pluralized.
The resource identifier should be in the URI template – not a query string parameter.
Use lower case, with hyphens to separate words, but try to use a single word whenever possible.
Use the resource path hierarchy to signify structure and scoping.
Good Example /customers/C12345/orders/O12345/items/I12345
Bad Example /customer?customerId=C12345&order=O12345&item=I12345
Where relationships are complex and deeply nested it is not advisable to go deeper than more than 3 relations deep.
Do not use a trailing forward slash (/) in URIs
Ideally there should be only 2 base URLs per resource. The first URL is for a collection; the second is for a specific element in the collection.
/transactions
/transactions/<transactionId>
Use the HTTP-provided media selection mechanisms.
Use the query component of a URI to filter collections or stores:
/positions?accountNumber=946432
Use the query component of a URI to paginate a collection:
/positions?offset=0&limit=10
Use path variables for direct ID of a noun:
For example, to retrieve an account with ID 65248 : GET /accounts/65248
Use parameters for non-direct IDs:
/positions?isdn=35346546
Do not use underscores (_) in resource names; use hyphens (-) instead. Avoid multi-word resource names altogether wherever possible. Use lowercase letters in URI paths.
Do not include file extensions in a URI.
Disallowed URL Characters
Due to cross-site vulnerability reasons, the following characters should not be used in a URL
BadCSSChars | <,>,',%22 | These are considered as cross-site scripting characters |
BadFormChars | <,>,&,%22 | Characters used in Html Form |
BadURLChars | //,./,/.,/*,*.,~,\,%00-%1f,%7f-%ff,%25,%25U,%25u | These are considered as bad URL characters |
Pagination and Partial Responses
Partial response allows developers to ask for exactly just the information they need.
It's almost always a bad idea to return every resource in a given database table, assuming that table is not fixed, and contains a potentially large number of rows.
There should be a reasonable attempt of consistency in results for collections that change often, given that each query is independent and stateless.
Use limit, offset, sortKey, and dir (asc or desc). These names are common, well understood and the concepts are present in database interfaces, and therefore easy for developers to use. The parameters offset and limit are zero-based.
The offset parameter defines the number of skipped records and limit defines the number of records to be returned. For example …?offset=100&limit=50 means that we are expecting the service to return records 101-150 from the result set.
When the limit parameter is not present, a given service should choose a reasonable default limit. For some services the default might be unlimited: for example, ...?offset=100 would mean return all records starting with record 101. For other services the default limit might be something finite such as 100: for example, ...?offset=100 would mean return records 101-200.
When the offset parameter is not present, the default is 0.
sortKey specified a field or field list, for which to sort first, before applying offset or limit.
dir specifies the sort direction – ascending or descending. The default sort direction is ascending.
Data Representation Formats
The default resource representation is JSON (Content-Type: application/json).
Tip: Always use a standard library to stream to JSON to ensure the data is well-formed and is valid JSON (e.g. com.google.gson.Gson)
Formatting
Attribute Name should be lowerCamelCase
Attribute Names, if query-able, should match their associated query parameter name exactly; for example
GET /positions?accountNumber=12345
should return,
{
"accountNumber" : 12345,
…
}
and not:
{
"acctNo" : 12345,
…
}
Lists are zero-based index.
For the Java value Null, or C value of NULL (0), use the text-based literal value "null".
Date and Timestamp
Dates can use either Coordinated Universal Time (UTC) or an offset from the UTC, thus avoiding issues with time zones and daylight saving times.
Dates should be returned in the format with timestamp YYYY-MM-DDTHH:MMZ with zero UTC offset so that conversion to respective time zone is accurate.
Examples:
Zero UTC offset -> 2014-10-17T10:12:30Z
Timestamp formats with seconds and milliseconds can be used for specific use cases : YYYY-MM-DDTHH:MM:SSZ / YYYY-MM-DDTHH:MM:SS.ssssssZ
Additional details on Date and Timestamp formats are available at W3, ISO 8601 Wiki and ISO 8601
Countries and Territories
Countries should be represented as 2 letter code e.g., US, DK, IN ISO_3166-1
subdivisions – WS-WA, US-CO, CA-BC, IN-AP. ISO-3166-2
Currencies
ISO 4217 specifies three letter currency codes for names of the currencies
List of codes are available in alphabet and numeric at Table A.1
Examples:
Language Tags
Best practices for the language tag are available at W3C \.
The new IANA registry is the right place to check sub tags
Examples:
Data Validation
Validation of incoming payload needs to be performed by the services.
Validation may include
Minimum, maximum length.
Enumeration Facets validation.
Special characters.
Application-dependent inter-object validation rules.
Tip: Use a standard REST framework to implement the validation functionality such as Spring MVC, Spring BootJersey or REST WS with Jackson.
Handling Representation Errors
Use a consistent form across the application to represent errors