Best practices for designing a RESTful API šŸ§‘ā€šŸ’»

šŸ’« Build a better API šŸ› 

Tirlea Ionut
5 min readApr 29, 2021
Photo by Jonas Leupe on Unsplash

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/ionut
AVOID:
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?

ā€œSometimes you really have no way to map the action to a sensible RESTful structure. For example, a multi-resource search doesnā€™t really make sense to be applied to a specific resourceā€™s endpoint. In this case, /search would make the most sense even though it isnā€™t a resource. This is OK ā€” just do whatā€™s right from the perspective of the API consumer and make sure itā€™s documented clearly to avoid confusion.ā€

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 Content
4xx 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=ionut
AVOID:
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: ...ā€
}
Photo by TrĆ  My on Unsplash

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

--

--

Tirlea Ionut

Sofware Developer šŸ‘©šŸ»ā€šŸ’» šŸ§  Kotlin enthusiast