10 things to guide you when you design an API
Tags: todayilearned, api
Published: 2021-01-22 10:27:20

![10 things to guide you when you design an API](https://dev-to-uploads.s3.amazonaws.com/i/82vzmvlgtr5z41h2dmow.jpg)

I want to share what I've learned to be nice to the developer when designing the new API with the best practices.

####1. Naming resource

My question was, Should this be singular or plural? I guess it depends on a specific resource. Mostly, we use the noun plural form of the name of a resource.

For example

```rb
# To create a customer
POST /customers

GET /customers # To get all customers

# To update the specified customer (#id)
PUT /customers/:id
```
You will notice that the naming resource is plural.

However, if you need to deal with the relation between resources, let's assume the customer has many orders, so you want to know all the customer's orders.

```rb
GET /customers/:id/orders
```

Or

```rb
# Allowing the customer to make a new order.
POST /customers/:id/orders
```

Unless the resource is singular, then it would be something like

```rb
# To get a user profile
GET /profile
GET /me
```

*Here's my suggestion below*

> Try not to use an abbreviation term like `POST /cust` (`customers`). It's hard to forecast. Bear in mind that you should build API to be *predictable*.

> Try not to use a verb in URI like `POST /create-customers` because CRUD (Create) helps us create a new record, so it's pretty redundant.

###2. Using version

Your API can allow versioning even though you think your API framework is tiny. Often, you don't have a choice because you need to change your response structure and rename the attribute, but versioning lets you escape this situation.

There are a variety of ways to apply to the version.

2.1) Place it in the URI prefix.

Ex: 

```rb
/v2/customers
```
But

> try not to use URI postfix to say the version like `/customers/api_version2`

2.2) Place it in the `Accept` Header with a custom.

Ex:

```rb
application/vnd.myapp+json;version=2
```

2.3) Place it in Query.

Ex:

```rb
/customers?api_version=2
```

If you add a new attribute, you don't need to build a new version of the API because you don't interrupt the business transition.

For example

```rb
GET /v1/customers/cust_12345

{
	"id": "cust_12345",
	"name": "jone doe"
	"email" "jone@mail" # Add a new `email` attribute. You can add it directly.
}
```

On the order hand, If you wish to rename the attribute from `name` to `fullname` you need to re-thinking what happenห if the person who uses your API is attempting to use the `name` attribute's gone.

Then you may decide to build a new version of `/v2`, or you add more attributes like `fullname` into `/v1`

###3. Separation Concern

It's a distinction between concerns that looks like in the Object-Oriented.

Let's assume you have the resource name `User`, which has several columns, such as `email`, `password`, `address`, `mobile_number`

You want the API to be able to change your password.

If it looks simple and generic to modify a user like the below one.

```rb
PATCH /v1/users/:id

{
	email: "john@mail",
	password: "abcdefg",
	confirmation_passowrd: "abcdefg"
}
```

After looking at the name of this endpoint, I should not recognize it immediately. And in my view, the number of comprehensive users would change.

This may not be convenient for the person who uses this API so that the API can be divided into two APIs;

> One for modifying the generic user details.

```rb
POST /v1/users/:id

{
	address: "new address",
	mobile_number: "new mobile number"
}
```

> One for just changing a password.

```rb
POST /v1/users/:id/password

{
	password: "abcdefg",
	confirmation_passowrd: "abcdefg"
}
```

###4. Time format

It should return times in UTC formatted to ISO8601. 

ISO8601 format: `YYYY-MM-DDTHH:MM:SSZ`

For example

```json
{
	"created_at": "2021-01-21T15:23:38Z"
}
```

Typically, I describe the name of the field base for the category between Date and DateTime that look like below; 

> `_on` suffixes for Date
> `_at` suffixes for DateTime

###5. camelCase or snake_case

It depends on your preference, but I feel that `snake_case` is easier to read than `camelCase` for attribute names.

###6. Errors

It's similar when you have an error on the website that displays an error with a thorough explanation.

As far as the API is concerned, it should also include a meaningful human-readable error message and support a unique error class for each type of error to the client.

For example

```rb
The status code for HTTP should be 404

{
	type: "account_not_found",
	message: "The account is not existing"
}
```

###7. Using HTTP verbs and status codes correctly 

HTTP offers a wonderful mechanism to inform the API to consumers whether the request is successful or not.

You may also refer to a lof of [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) to apply to the API.

#### HTTP verbs

- `GET` to retrieve a resource.
- `POST` to create a resource (Sometime, you might use it without creating any record)
- `PATCH` to modify the partial resource
- `PUT` to replace a resource or collect of a resource.
- `DELETE` to delete a resource.


#### HTTP status codes

- `2xx Success` Everything's going smoothly.
- `200 OK` It's a successful response that everything goes well.
- `201 Created` Most of the time, it's used to `POST` that results in a creation.
- `204 No content` It is also used for `DELETE`, which resource has been removed and the returned body is null.
- `400 Bad Request` The request is invalid/unacceptable, or an appropriate parameter is lacking.
- `401 Unauthorized` Mostly, It's used for invalid authentication.
- `404 NotFound`
- `429 Too many requests`
- `5xx` Something went wrong with us.

###8. Pagination

You might fail to worry about how large the data is since it returns a lot of records at once, so you should have a way to limit the number of records per request.

```rb
GET /v1/customers?page=2&per_page=30
```

###9. Rate limiting

You might be surprised if someone attempts to spam your API unreasonably. So you may start implementing a rate-limit early.

You may use [Redis](https://redis.io/) with EXPIRE feature to limit the specified person's request.

###10. Good Documentation

You should have good API documentation that should be reliable and simple for the developer to understand. I think all developers (including me) enjoy good examples; not only do they have code samples like `curl --` but they can cover all test cases like Postman Examples or Swagger Examples.

See [Postman Examples](https://learning.postman.com/docs/sending-requests/examples/) and [Swagger Examples](https://swagger.io/docs/specification/adding-examples/) for more details.