In order to design great RESTful APIs, we should follow the best practices or guidelines to implement and maintain them effectively. Today, we would like to share the following best practices:
General concepts
- KISS: Anyone should be able to use the API without having to refer to the documentation.
- Use standard, concrete and shared terms, not the specific business terms or acronyms.
- Never allow application developers to do things in more than one way.
- Design your API for clients (application developers), not for data.
- Target major use cases first, deal with exceptions later.
- CURL: using CURL to share examples, which can be easily copy/paste.
- Resources shouldn’t be nested more than two level deep : GET /ads/id
- Considering the following five subdomains:
- Production: – https://api.mycompany.com
- Tests – https://api.sandbox.mycompany.com
- Developer portal – https://developers.mycompany.com
- Production with security – https://oauth2.mycompany.com
- Tests – https://oauth2.sandbox.mycompany.com
- Security : OAuth2 & HTTPS
- Using OAuth2 to manage Authorization
- Using HTTPS for every API/OAuth2 request.
- Use json to send/receive data
The benefits from using JSON described as below:
- it’s easier to use, write and read
- it’s faster and consumes less memory space
- it doesn’t need special dependencies or packages to parse it
- every single meaningful programming language has great support for it
- Use nouns instead of verb for resources
So let’s start with API endpoints. The rules here are simple:
- use nouns instead of verbs
- use plural instead of singular
Regarding endpoint naming: try to use single words instead of multi words. If you really have to use multi words then use hyphens between them. Using all lowercase letters in URIs. My idea: I would recommend using snake_case. I find snake_case much easier to read and that is why all of our APIs use snake_case.
Good:
GET ads
POST /ads
GET /ads/23
PUT /ads/23
DELETE /ads/23
Bad:
GET /ad/23
GET /listAllAds
POST /ad/create
PUT /updateAds/23
GET /userComments/2
- Using HTTP methods to mean something
Each HTTP method has been designed to be used in certain situations.
- GET retrieves a representation of the resource at the specified URI. The body of the response message contains the details of the requested resource. You should use the GET method when you wish to read data. Not store, not update, not change data. Only read the data
- POST creates a new resource at the specified URI. The body of the request message provides the details of the new resource. Note that POST can also be used to trigger operations that don’t actually create resources. When you make a POST request everyone in the world expects you to usually STORE something
- PUT either creates or replaces the resource at the specified URI. The body of the request message specifies the resource to be created or updated. PUT requests are most often used in the context of updating things
- PATCH performs a partial update of a resource. The request body specifies the set of changes to apply to the resource. A patch request is meant to be used to update resources again but unlike PUT it should update only the changed data whereas PUT can and should update the entire resource
- DELETE removes the resource at the specified URI.When you wish to delete resources simply use the DELETE method.
For example
Resource | POST | GET | PUT | DELETE |
/ads | Create a new ad | Retrieve all ads | Bulk update of ads | Remove all ads |
/ads/1 | Error | Retrieve the details for ad 1 | Update the details of ad 1 if it exists | Remove ad 1 |
/ads/1/reviews | Create a new review for ad 1 | Retrieve all reviews for ad 1 | Bulk update of reviews for ad 1 | Remove all reviews for ad 1 |
- Using status codes to be meaningful in error handling
- 200: result of operation in the response body
- 201: create new resource
- 204: no content if there is no result to return
- 400 – 499: client side errors
- 500-599: server side errors
- Use Nesting on Endpoints to Show Relationships
- Good:
- Different ads posted by users: https://openreal.api.com/ads/users
- The ads have their reviews, so to retrieve reviews, endpoint can be https://openreal.api.com/ads/id/reviews
- Note : should avoid nesting more than 3 levels because it makes api less readable. In this case, we recommend that we use HATEOAS to enable navigation to related resources
- Use Filtering, Sorting, and Pagination to Retrieve the Data Requested
- API’s database can get very large. So, it makes the system very slow. Therefore, we need a way to filter the items.
- Filtering, sorting, paginating are all actions to increase the performance. This lets only retrieve, sort and arrange data into pages, so the server doesn’t get too occupied with requests
- Use SSL (Secure Socket Layer) for security
Treat our API the same way we would our house.
- Use a Bearer token for authentication.
- Require HTTPS / TLS / SSL to access your APIs. OAuth2 Bearer tokens demand it. Unencrypted communication over HTTP allows for simple eavesdropping and impersonation.
- Cache data to improve performance
We can add caching to return data from the local memory cache instead of querying the database to get the data every time we want to retrieve some data that users request. The good thing about caching is that users can get data faster. However, the data that users get may be outdated. This may also lead to issues when debugging in production environments when something goes wrong as we keep seeing old data.
There are many kinds of caching solutions like Redis, in-memory caching, and more. We can change the way data is cached as our needs change.
- Be clear with versioning
REST API should have different versions so that we don’t force users to migrate to a new version..
Using semantic versioning to name versions: major.minor.patch for example 1.0.0
It depends on your needs that you name the version more convenient.
I prefer to use: https://openreal.api.com/v1/
- Provide accurate API document
The good document for the API will help users learn and figure out how to use it correctly.
The documentation should contain:
- relevant endpoints of the API
- example requests of the endpoints
- implementation in several programming languages
- messages listed for different errors with their status codes
Tools for writing the API document: Swagger or Postman.