10 tips to create comfortable REST API
Tags: webdev, backend, restapi, api
Published: 2021-07-23 09:38:18

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
```
**Good:**
```
DELETE /users/{userId}
PUT /bookings/{bookingId}
```

## 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
```
**Good:**
```
POST /users/{userId}/books/{bookId}/attach
POST /users/{userId}/notifications/send - send notify to user
```

## 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}
```

## 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}
```

**Good:**
```
GET /bookings/travellers/{travellerId}
```

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
```

**Good:**
```
GET /users/{userId}
POST /tickets/{ticketId}/book
```

## 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
```

**Good:**
```
GET /tickets/booked
POST /users/gold
```

## 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, 
    ...
}
```

**Good:**
```
GET /book/{bookId}
{
    "status": 0,
    "message": "ok",
    "data": {...}
}
```

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}
```

**Good:**
```
GET /users/{userId}
POST /ticket/{ticketId}/gold
```

### 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"
}
```

**Good:**
```
{
    "id": "fb6ad842-bd8d-47dd-b7e1-68891d8abeec",
    "name": "soccer3000",
    "providerId": 1455,
    "createdAt": "25.05.2020"
}
```

## 10. Use Content-Type

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

**Badly:**
```
GET /tickets.json
GET /tickets.xml
```

**Good:**
```
GET /tickets
// in headers
Сontent-Type: application/json
// or
Сontent-Type: application/xml
```

## 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!