DEV Community

Valeriy
Valeriy

Posted on

10 tips to create comfortable REST API

I'm backend engineer and biggest part of my career based on creating different APIs for services. Tips for this article were collected based on the most frequently faced issues on designing stage of team projects or using external APIs.

Chances are, you've come across terrible API providers. Working with them, as a rule, is associated with increased emotionality and misunderstanding. Some of these problems can be avoided by designing the application interface using the tips below.

1. Do not use verbs in url*

* - if you are going to implement one of CRUD-action

The CRUD request methods are responsible for the action with the resource: POST - create, GET - read, PUT / PATH - update , DELETE - delete (you know :)).

Badly:

POST /users/{userId}/delete - delete user
POST /bookings/{bookingId}/update - update booking
Enter fullscreen mode Exit fullscreen mode

Good:

DELETE /users/{userId}
PUT /bookings/{bookingId}
Enter fullscreen mode Exit fullscreen mode

2. Use verbs in url

You can use verbs in url to describe something diff than CRUD-action.

Badly:

POST /users/{userId}/books/{bookId}/create - link book with user
Enter fullscreen mode Exit fullscreen mode

Good:

POST /users/{userId}/books/{bookId}/attach
POST /users/{userId}/notifications/send - send notify to user
Enter fullscreen mode Exit fullscreen mode

3. Define new entities

Above there is an example of adding a book to a user, perhaps the logic of your application implies a list of favorites, then the route may be like this:

POST /favorite/{userId}/{bookId}
Enter fullscreen mode Exit fullscreen mode

4. Try to use one resource identifier

This means if you have one-to-many records, for example: booking -> travellers, it will be enough for you to use only traveler identifier in the request.

Badly:

# getting travellers data
GET /bookings/{bookingId}/travellers/{travellerId}
Enter fullscreen mode Exit fullscreen mode

Good:

GET /bookings/travellers/{travellerId}
Enter fullscreen mode Exit fullscreen mode

Also note that /bookings/travellers is better than just /travellers. It's good to stick to the data hierarchy in your API.

5. All resources in plural

Badly:

GET /user/{userId} - getting users data
POST /ticket/{ticketId}/book - ticket booking process
Enter fullscreen mode Exit fullscreen mode

Good:

GET /users/{userId}
POST /tickets/{ticketId}/book
Enter fullscreen mode Exit fullscreen mode

6. Make the most of HTTP statuses

The easiest way to handle errors is to respond with an appropriate status code. In most cases, this status alone can provide comprehensive information about the result of request processing. Some of the most common response codes:

  • 400 Bad Request - The client sent an invalid request, for example, a required request parameter is missing.

  • 401 Unauthorized - The client was unable to pass mandatory server authentication to process the request.

  • 403 Forbidden - The client is authenticated but does not have permission to access the requested resource.

  • 404 Not Found - The requested resource does not exist.

  • 409 Conflict - This response is sent when the request conflicts with the current state of the server. Example: trying to make an booking twice.

  • 500 Internal Server Error - A general error has occurred on the server.

  • 503 Service Unavailable - The requested service is not available. Example: slow work of backend code and, consequently, freezing of the general workflow of service.

7. Resource get modifiers

The routing logic may not be related to the project architecture or database structure. For example, the database contains quizzes and passed quizzes - two separate tables and entities (quizzes and passed_quizzes). But for api, it can be just quizzes, and passed quizzes are a modifier.

Route example: /quizzes and /quizzes/passed. Here quizzes - resource, passed - modifier.

Badly:

GET /passed-quizzes - getting passed quizzes
GET /booked-tickets - getting booked tickets
POST /gold-users - creating gold user
Enter fullscreen mode Exit fullscreen mode

Good:

GET /tickets/booked
POST /users/gold
Enter fullscreen mode Exit fullscreen mode

8. Choose one response structure

When on two different API requests can be received completely different response - it's sadly.

Try to form one clear structure that you will always adhere to. It will also be cool to include service fields that carry additional information.

Badly:

GET /book/{bookId}
{
    "name": "Harry Potter and the Philosopher's Stone",
    "genre": "fantasy",
    "status": 0, # статус вашего приложения
    "error": false, 
    ...
}
Enter fullscreen mode Exit fullscreen mode

Good:

GET /book/{bookId}
{
    "status": 0,
    "message": "ok",
    "data": {...}
}
Enter fullscreen mode Exit fullscreen mode

In this example, 3 fields are universal and can be used for any responses from your API. status - request-handling status of application. messages - text by which API-client can figure that happening. Both fields inform additional information about request processing, but they shouldn't include application data.

For example, in application at one time, a user can take only one quiz. Then a request to start new quiz can reply the 409 status code. In the status and message fields there will be additional information why the error has occurred.

9. All parameters and json in camelCase

9.1 Request params

Badly:

GET /users/{user-id}
GET /users/{user_id}
GET /users/{userid}
Enter fullscreen mode Exit fullscreen mode

Good:

GET /users/{userId}
POST /ticket/{ticketId}/gold
Enter fullscreen mode Exit fullscreen mode

9.2 In body of request or response

Badly:

{
    "ID": "fb6ad842-bd8d-47dd-b7e1-68891d8abeec",
    "Name": "soccer3000",
    "provider_id": 1455,
    "Created_At": "25.05.2020"
}
Enter fullscreen mode Exit fullscreen mode

Good:

{
    "id": "fb6ad842-bd8d-47dd-b7e1-68891d8abeec",
    "name": "soccer3000",
    "providerId": 1455,
    "createdAt": "25.05.2020"
}
Enter fullscreen mode Exit fullscreen mode

10. Use Content-Type

Don't make special routes for types, use Content-Type header instead.

Badly:

GET /tickets.json
GET /tickets.xml
Enter fullscreen mode Exit fullscreen mode

Good:

GET /tickets
// in headers
Сontent-Type: application/json
// or
Сontent-Type: application/xml
Enter fullscreen mode Exit fullscreen mode

The End

The tips listed above are not the whole list of ways to make the API better. For further study, I recommend that you discover the REST API specifications and the list of http status codes (you will be surprised how many of them and what situations they cover).

Let's share in comments your recommendations for building awesome APIs.

Happy coding!

Top comments (0)