Method | Description |
---|---|
GET | Retrieve a resource or a list of resources. |
POST | Create a resource, or execute a complex operation on a resource. |
PUT | Update a resource. |
PATCH | Perform a partial update to a resource. |
DELETE | Delete a resource. |
HTTP Header Name | Description |
---|---|
Accept | This header advertises which content types, expressed as MIME types, the client is able to understand. It is assumed that APIs support application/json. |
Accept-Charset | This header advertises which character set the client is able to understand. This value SHOULD include utf-8. |
Authorization | This header contains the credentials to authenticate a user. For example: Bearer {JWT Token} |
Content-Language | This entity header is used to describe the language(s) intended for the audience. APIs must provide this header in the response. Example: Content-Language: pt-BR |
Content-Type | This entity header is used to indicate the media type of the resource. This value should include application/json. |
GET api.myservice.com/v1/customers
The endpoint URLs should be in the following format:
GET /v1/resource
GET /v1/resource/:id
GET /v1/resource/:id/subresource
GET /v1/resource/:id/subresource/:id
for composite names use kebab-case.
Use plural nouns for resources and subresources.
GET /v1/customers
GET /v1/customers/1e92EA/addresses
GET /v1/customers/1e92EA/addresses/321e5EA
The IDs in the endpoint URLs should not be sequential.
Trailing slash is optional.
Use envelope to avoid some potentials hacks. Click here to see more.
For the JSON use snake_case or camelCase as you prefer. Snake case is 20% easier to read but it is up to you.
Codes | Description |
---|---|
Standards | |
200 OK | When everything is okay. |
201 Created | Response to POST method execution to indicate successful creation of a resource. |
202 Accepted | Asynchronous method execution to specify the server has accepted the request and will execute it at a later time. |
204 No Content | When everything is okay, but there’s no content to return. |
405 Method Not Allowed | The server has not implemented the requested HTTP method. |
406 Not Acceptable | When it cannot return the payload of the response using the media type requested by the client. For example, if the client sends an Accept: application/xml header, and the API can only generate application/json. |
415 Unsupported Media Type | When the media type of the request's payload cannot be processed. For example, if the client sends a Content-Type: application/xml header, but the API can only accept application/json. |
500 Internal Server Error | When the server throws a completely unexpected error. |
Data Errors | |
400 Bad Request | When the requested information is incomplete or malformed. |
404 Not Found | When everything is okay, but the resource doesn’t exist. |
409 Conflict | When a conflict of data exists, even with valid information. |
422 Unprocessable Entity | When the requested information is okay but invalid. |
Auth Errors | |
401 Unauthorized | When an access token isn't provided or is invalid. |
403 Forbidden | When an access token is valid, but requires more privileges. |
Sources: | |
Paypal - API Design Guidelines | |
RESTful API Design Tips from Experience |
Data errors examples:
If the email field is missing, return a 400.
If the password field is too short, return a 422.
If the email field isn’t a valid email, return a 422.
If the email is already taken, return a 409.
422 Unprocessable Entity
{
"data": {
"error": "FIELDS_VALIDATION_ERROR",
"description": "One or more fields raised validation errors."
"fields": {
"email": "Invalid email address.",
"password": "Password too short."
}
}
}
409 Conflict
{
"data": {
"error": "EMAIL_ALREADY_EXISTS",
"description": "An account already exists with this email."
}
}
Use query string parameter page starting at 1 to return a limited number of results. The page_size query string has a maximum of 1000 and default page_size of 20 for the pagination.
GET /v1/customers/?page=5&page_size=300
Use sort_by query string parameters to order the resources as specificed by the client.
GET /v1/customers/?sort_by=name,weight,-age
// an SQL example
SELECT name, weight, age FROM customers ORDER BY name ASC, weight ASC, age DESC;
The fields are separeted by commas and their order should be respected. The minus symbol denotes DESC order and no minus symbol denotes ASC order.
The date and time string MUST conform to the date-time universal format defined in section 5.6 of RFC3339.
All APIs MUST only emit UTC time (aka Zulu time or GMT) in the responses.
When processing requests, an API SHOULD accept full-date, date-time or full-time fields that contain an offset from UTC. For example, 2016-09-28T18:30:41.000+05:00 SHOULD be accepted as equivalent to 2016-09-28T13:30:41.000Z.
(PayPal - Date, Time and Timezone)[https://github.com/paypal/api-standards/blob/master/api-style-guide.md#date-time-and-timezone]
Create a new resource and return the resource object.
POST /v1/customers
{
"name": "Vando",
"email": "vando@bee"
}
201 Created
{
"id": "1e92EA",
"name": "Vando",
"email": "vando@bee"
}
Get a single resource using the ID in the URL query string.
GET /v1/customers/1e92EA
200 OK
{
"data": {
"id": "1e92EA",
"name": "Vando",
"email": "vando@bee"
}
}
Get a list of resources plus the meta information about this list such as total items and pages.
GET /v1/customers
200 OK
{
"data": {
"meta": {
"total_items": 100,
"total_pages": 10
},
"items": [
{ ... },
...
]
}
}
Update partially a single resource.
PATCH /v1/customers/1e92EA
{
"name": "Vando Almeida"
}
204 No Content
Delete a single resource.
DELETE /v1/customers/1e92EA
204 No Content
I prefer to use field loopups for filtering inspired by Django Field Lookups and Django Tastypie.
Lookup syntax: field__lookuptype=value
Endpoint example:
GET /v1/customers?age__gt=21&age__lt=33&name__icontains='Mario'
Example lookups:
ne (not equal)
ie (ignore case - equal)
contains
icontains (ignore case - contains)
in
gt (greater than)
gte (greater than - equal)
lt (lower than)
lte (lower than - equal)
startswith
istartswith (ignore case - starts with)
endswith
iendswith (ignore case - ends with)
Another approach to filtering is to use a json-object-like as query parameter as described in the guide below: Kinvey - Modifiers
Another approach is the Open Data Protocol (OData): URL Conventions (OData Version 3.0) - Logical Operators
RESTful API Design Tips from Experience - Avoid Unnecessary Query Strings
A simple endpoint that can indicate if your API instance is alive and does not need to be restarted. It’s also useful for easily checking what version of the API is on any machine at any time, without authentication.
GET /
200 OK
{
"version": "1.2.3"
}
RESTful API Design Tips from Experience - Implement a “Health-Check” Endpoint
Versioning: Semantic Versioning
You should beware. X-Request-ID support means that you can easily trace an HTTP request all the way from a client to your backend web processes (via our proxies).
Used for a single request with a list of resources.
This kind of requisition should be atomic.
Recommended to use bulk at the end of the URL.
POST /v1/customers/bulk
{
items: [
{ ... },
{ ... },
{ ... },
...
]
}
200 OK
{
batch_result: [
{ < Success Response > },
{ < Success Response > },
{ < Error Response > },
{ < Error Response > }
]
}
Type | Description |
---|---|
Country Code | APIs must use the ISO 3166-1 alpha-2 two letter country code standard. |
Currency Code | Currency type must use the three letter currency code as defined in ISO 4217. For quick reference on, see ISO_4217. |
Language Code | IETF specified by RFC 5646 and RFC 4647. For quick reference on, see Microsoft - Language Codes. |
Compress your response using GZIP, it will save time and bytes.
See more: How much time should you save? Best Practices for Designing a Pragmatic RESTful API
How to GZIP: nginx - Enable GZIP
RESTful API Design Tips from Experience
PayPal - API Design Patterns And Use Cases