Best practices for designing a RESTful API š§āš»
š« Build a better API š
REST APIs are the most commonly used web services in the modern world. Because of that, proper design is really important. In the following article, I will highlight some tips that I learned over time, which you can keep in mind when designing your RESTful APIs.
To simplify some concepts I will illustrate them by examples, showcasing a fictive medium.com API. Also, check this page if you are not familiar with REST terminology.
Versioning
If youāre going to design a REST API for any client service, you need to prepare for any eventual changes. This is usually done by providing a āversion-namespaceā for your RESTful API. In simple words, this will be just a prefix (/v1/
, /v2/)
added to the start of your API path (but it doesnāt necessarily need to be numeric). Versioning helps you iterate faster when needed changes are identified. Other approaches might use a custom header or the HTTP accept header.
GET api.medium.com/v1/articlesGET api.medium.com/v2/articlesGET api.medium.com/phoenix/articles
Keep in mind that any breaking changes should result in a change to the version of your API.
Common examples of breaking changes include:
- Modifying a resource URI
- Deleting a response field
- Modifying required query parameters
- Modifying authentication
You should continue to provide support for the previous version for a set period of time. In the meantime, you can use the Deprecation HTTP Header Field to signal to the clients that a resource has been deprecated.
Documentation
An API is as good as its documentation. Your documentation must completely describe the APIās functionality and should be accurate, especially if your API is public! Also, you can include any deprecation and update schedules in the documentation.
Check Swagger Open API to see how you can use it to streamline the documentation for your RESTful API: Documenting Your Existing APIs: API Documentation Made Easy with OpenAPI & Swagger
Use the right HTTP methods
When designing your REST API you should use the right HTTP methods. Hereās a list of the commonly used methods, each of them having a specific meaning, providing a strategy to handle CRUD actions:
- POST is used to submit an entity to the specified resource
- GET requests a representation of the specified resource.
- PUT/PATCH for updating a resource (whatās the difference?)
- DELETE deletes the specified resource
To learn more about HTTP request methods, and whether they are safe, idempotent, or cacheable check this.
Use nouns over verbs
You should be keeping verbs out of your URLs since the HTTP methods already describe a CRUD action. Having verbs instead of nouns in the URL can make working with your resources confusing.
DO:
GET /authors
GET /authors/ionutAVOID:
GET /getAllAuthors
GET /getAuthorByName/ionut
Of course, there can be actions that donāt fit in the world of CRUD operations. Read this thread over StackExchange to find out How to design a REST API to handle non-CRUD operations?
Use the right HTTP Status Codes
You should make use of the right HTTP status codes! However, donāt overuse them. Most API providers use only a small subset of HTTP Status Codes as there are a lot of them (you can find the complete list here). For example, Netflix uses just 9!
You should define a set of status codes when starting building your API and consistently use them. Here are the most used ones :
2xx Success
200 OK - this is the standard response for successful requests
201 Created - the request was successful and resulted in the creation of a new resource
204 No Content4xx Client Errors
400 Bad Request - the server cannot process the request due to a client error (malformed request syntax, invalid parameters)
404 Not Found - the requested resource could not be found but may be available in the future
409 Conflict - indicates that the request could not be processed because of conflict in the current state of the resource
418 I'm a teapot - just an Easter Egg, indicating that the server refuses to brew coffee, because it's a teapot šµ5xx Server Errors
500 Internal Server Error - a generic error message when an unexpected condition occurs
502 Bad Gateway - the server was acting as a gateway or proxy and received an invalid response from the upstream server
Return the updated resource
When updating any resource itās good practice to return the updated resource as the response to a successful POST
, PUT
, or PATCH
request! In case of DELETE
, you should use the 204 - No Content HTTP Status Code. This is enough to indicate a successful response without any arbitrary "information".
Generally speaking, in case of a successful request, I use the following:
GET: 200 OK
POST: 201 Created
PUT: 200 OK
PATCH: 200 OK
DELETE: 204 No Content
Donāt forget to be consistent! If you choose a 204 Status code for indicating a successful DELETE
you should use that status code for any DELETE
!
Use query parameters
Sometimes, the usage of query parameters can be more meaningful in your API. Check the following example:
DO:
GET /articles/?author_name=ionutAVOID:
GET /articles/ionut
GET /getArticleByAuthor/ionut
Avoid nesting resources
Letās say we want to retrieve a list of articles published by a named author . The first option will be to nest the articles resource under the authors resource.
GET /author/ionut/articles
However, this makes it difficult to see what resource is requested (author or articles). Because of that, I try to avoid nesting. In this example, we can use a Query String instead.
GET /articles/?author_name=ionut
Use error payloads
It is always good practice to keep a set of error messages and error codes. Define a clear error payload, and use it consistently. If you want to use error codes stick to a small set to avoid confusion.
{
ācodeā: āINVALID_PARAMETERā
āmessageā: āInvalid parameter <{name}>! Supported formats: ...ā
}
Donāt forget: Keep it simple āØ!
If you find this useful, please click the clap š button below a few times to show your support! Donāt forget, sharing is caring! š Happy coding ā !
Ionut