In this document we will gather information regarding the standards and definitions necessary for an API to be in according to the REST standard.
The purpose of this guideline is to make it easy to apply REST in our APIs, so let's apply some concepts and understand some fundamentals.
The application's main endpoint must return the name of the project and its current version.
Request:
http://localhost:5000/
Response:
{"app": "project-name:1.0.0"}
Collections are for example listings and data types.
Example:
GET /products
Instances are collection items.
Example:
GET /products/0871b2de-7a97-41bc-8d24-aafae8f5b8be
The behaviors of a REST API are delimited by verbs and HTTP status:
| HTTP Verb | Description | Collection behavior | Instance Behavior | Examples |
|---|---|---|---|---|
| POST | Instance creation | 201 - Created | 404 - Not Found 409 - Conflict - If the record already exists |
Request: POST /products Response: Header Location with new ID 201 Created Location: /products /0871b2de-7a97-41bc-8d24-aafae8f5b8be |
| GET | Reading collections or instances Pagination Sort Filters |
200 - OK | 200 - OK - Reading a single item 404 - Not Found - When the ID is invalid |
Request from a collection: GET /products Request from an instance: GET /products/0871b2de-7a97-41bc-8d24-aafae8f5b8be Example of a collection being filtered: GET /products?fields=name,description&sort=name&order=asc&offset=10&limit=20 Other examples: GET /customers/ GET /customers/0871b2de-7a97-41bc-8d24-aafae8f5b8be/orders GET /customers/0871b2de-7a97-41bc-8d24- aafae8f5b8be/orders/2693be21-1b16-4a2d-b91f-71b69724d54b |
| PUT | Full Upgrade (Replace) | 405 - Method not Allowed | 200 - OK 404 - Not Found - When the ID is invalid |
Request: PUT /products/0871b2de-7a97-41bc-8d24-aafae8f5b8be |
| PATCH | Atomic Update | 405 - Method not Allowed | 200 - OK 404 - Not Found - When the ID is invalid |
Request: PATCH /products/0871b2de-7a97-41bc-8d24-aafae8f5b8be |
| DELETE | Deleting Items | 405 - Method not Allowed | 200 - OK 404 - Not Found - When the ID is invalid |
Request: DELETE /products/0871b2de-7a97-41bc-8d24-aafae8f5b8be |
Each resource must have a dedicated URI or its own address.
The operations must consist of the combination of URIs and HTTPs verbs.
Let's say we are describing an ordering system in which we have customers, orders, categories, and products. We will use URIs to describe and perform operations on these items:
To perform a list of clients, we must consume the following URI with the HTTP GET verb:
GET /customers
To create a client, we need to consume the following URI with the HTTP POST verb:
POST /cutomers
To update a client, we need to consume the following URI with the HTTP PATCH verb:
PATCH /customers/0871b2de-7a97-41bc-8d24-aafae8f5b8be
To perform a partial update of a client, we need to consume the following URI with the HTTP PUT verb:
PUT /customers/0871b2de-7a97-41bc-8d24-aafae8f5b8be
To replace a client, we need to consume the following URI with the HTTP PUT verb:
PUT /customers/0871b2de-7a97-41bc-8d24-aafae8f5b8be
To delete a client, we need to consume the following URI with the HTTP DELETE verb:
DELETE /customers/0871b2de-7a97-41bc-8d24-aafae8f5b8be
<p>TODO:</p>
Map more complex examples here
Normally we will work with APIs in JSON format, so use application/json by default.
Content-Type: application/json
Preferably use something straightforward like:
https://{service-name-api-name}.site.com.br
When you have a single API:
https://api.site.com.br/{service-name}/{api-name}
In this section we provide guidance on configuring your service.
Service versioning is the responsibility of the API, being managed via routes and configuration files, making facilitated the maintenance or availability of new routes.
The API Gateway must point the route to the application and the rest can be managed by the same, the type of integration to be performed in this case is via Proxy.
https://{service-name}.site.com.br/v1/{resource-name}/
In our APIs this is not a very common scenario, but for some context it may be necessary to support different media types, so let's leave an example here.
Requsição:
GET /products
Content-Type: application/json
Response:
200 OK
Content-Type: application/json
{
"success": true,
"label": "common.success",
"code": 1,
"message": "Successful request",
"params": [],
"control": {
"count": 1,
"limit": 20,
"offset": 0,
"total": 100
},
"data": [
{
"id": "1",
"uuid": "0871b2de-7a97-41bc-8d24-aafae8f5b8be",
"name": "Pencil",
"description": "Common pencil"
}
],
"links": [],
"meta": {
"first": "/products?offset=0&limit=20",
"href": "/products?offset=0&limit=20",
"last": "/products?offset=4&limit=20",
"next": "/products?offset=1&limit=20",
"previous": ""
}
}Requsição:
GET /products
Content-Type: application/xml
Response:
200 OK
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<success>true</success>
<label>common.success</label>
<code>1</code>
<message>Successful request</message>
<params/>
<control>
<count>1</count>
<limit>20</limit>
<offset>0</offset>
<total>100</total>
</control>
<data>
<id>1</id>
<uuid>0871b2de-7a97-41bc-8d24-aafae8f5b8be</uuid>
<name>Pencil</name>
<description>Common pencil</description>
</data>
<links/>
<meta>
<first>/products?offset=0&limit=20</first>
<href>/products?offset=0&limit=20</href>
<last>/products?offset=4&limit=20</last>
<next>/products?offset=1&limit=20</next>
<previous></previous>
</meta>
</root>Below we will present recommendations and rules for the composition of documents.
Preferably use camelCase, as javascript handles better and is also part of its convention.
By default use the ISO 8601 format, other possible alternatives are:
- ATOM
- RFC3339
- W3C
Example in PHP:
/* Constantes */
const string ATOM = "Y-m-d\TH:i:sP";
const string ISO8601 = "Y-m-d\TH:i:sO";
const string RFC3339 = "Y-m-d\TH:i:sP";
const string W3C = "Y-m-d\TH:i:sP";Examples:
2021-09-16T16:05:00.343Z
2021-09-16T16:05:00.426914-03:00
Utilizar o timezone UTC preferencialmente, ou ao menos ter a indicação do fuso horário na string da data:
Neste exemplo abaixo temos o timezone BRT:
2021-09-16T16:05:00.426914-03:00
You can configure your API not to return the body in some cases of POST requests, passing a flag via querystring by adding the _body parameter.
Request:
POST /products?_body=false
Response:
201 Created
Location: /products/0871b2de-7a97-41bc-8d24-aafae8f5b8be
No content
Request:
GET /v1/cache/systems
Response:
200 OK
{
"success": true,
"label": "common.success",
"code": 1,
"message": "Success",
"params": [],
"data": [
{
"id": 1,
"hash": "35070aaf185288daa04ed8fb519c11a99aa8e754",
"name": "Brain",
"company_id": 1,
"squad": "drop-shipping-logistic"
},
{
"id": 2,
"hash": "dae51a2482328610a6b3261778768776132e633f",
"name": "Eagle",
"company_id": 1,
"squad": "drop-shipping-logistic"
},
{
"id": 3,
"hash": "35b492c8dd4e13bcccdc0cf4c52e2b1eabc5b463",
"name": "Delivery Simulator",
"company_id": 2,
"squad": "webstore-buy"
},
{
"id": 4,
"hash": "e213982e543d6887ae38cfcf001f71590294a1e3",
"name": "Fretzy Deliver Time Reducer",
"company_id": 2,
"squad": "webstore-buy"
}
],
"control": {
"offset": 0,
"limit": 4,
"total": 25,
"count": 4
}
}Request:
GET /v1/cache/systems/35070aaf185288daa04ed8fb519c11a99aa8e754
Response:
200 OK
{
"success": true,
"label": "common.success",
"code": 1,
"message": "Success",
"params": [],
"data": {
"id": 1,
"hash": "35070aaf185288daa04ed8fb519c11a99aa8e754",
"name": "Brain",
"company_id": 1,
"squad": "drop-shipping-logistic"
}
}Request:
GET /v1/cache/systems/35070aaf185288daa04ed8fb519c11a99aa8e754
Response:
404 Not Found
{
"success": false,
"label": "common.error.find_error",
"code": 14,
"message": "Unable to find the record",
"params": [
"35070aaf185288daa04ed8fb519c11a99aa8e754"
]
}Request:
DELETE /v1/cache/systems
Response:
200 OK
{
"success": true,
"label": "common.cache_deleted_with_success",
"code": 1,
"message": "Caches deleted with success",
"params": [],
"data": {}
}Request:
DELETE /v1/cache/systems
Response:
500 Internal Server Error
{
"success": false,
"label": "common.error.delete_list_error",
"code": 25,
"message": "Unable to delete the records",
"params": [
]
}Request:
DELETE /v1/cache/systems/35070aaf185288daa04ed8fb519c11a99aa8e754
Response:
200 OK
{
"success": true,
"label": "common.cache_deleted_with_success",
"code": 1,
"message": "Caches deleted with success %s",
"params": [
"35070aaf185288daa04ed8fb519c11a99aa8e754"
],
"data": {}
}Request:
DELETE /v1/cache/systems/35070aaf185288daa04ed8fb519c11a99aa8e754
Response:
500 OK
{
"success": false,
"label": "common.error.delete_error",
"code": 26,
"message": "Unable to delete the record %s",
"params": [
"35070aaf185288daa04ed8fb519c11a99aa8e754"
]
}The IDs must be opaque and not strings in order to avoid problems with explicit data collection by bots or even attacks.
Use hash or UUIDs;
Example:
Hash: 35070aaf185288daa04ed8fb519c11a99aa8e754
UUID: 0871b2de-7a97-41bc-8d24-aafae8f5b8be

