DEV Community

loading...

10 things to guide you when you design an API

nuttapon profile image Nuttee ・5 min read

10 things to guide you when you design an API

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

# To create a customer
POST /customers

GET /customers # To get all customers

# To update the specified customer (#id)
PUT /customers/:id
Enter fullscreen mode Exit fullscreen mode

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.

GET /customers/:id/orders
Enter fullscreen mode Exit fullscreen mode

Or

# Allowing the customer to make a new order.
POST /customers/:id/orders
Enter fullscreen mode Exit fullscreen mode

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

# To get a user profile
GET /profile
GET /me
Enter fullscreen mode Exit fullscreen mode

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:

/v2/customers
Enter fullscreen mode Exit fullscreen mode

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:

application/vnd.myapp+json;version=2
Enter fullscreen mode Exit fullscreen mode

2.3) Place it in Query.

Ex:

/customers?api_version=2
Enter fullscreen mode Exit fullscreen mode

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

GET /v1/customers/cust_12345

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

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.

PATCH /v1/users/:id

{
    email: "john@mail",
    password: "abcdefg",
    confirmation_passowrd: "abcdefg"
}
Enter fullscreen mode Exit fullscreen mode

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.

POST /v1/users/:id

{
    address: "new address",
    mobile_number: "new mobile number"
}
Enter fullscreen mode Exit fullscreen mode

One for just changing a password.

POST /v1/users/:id/password

{
    password: "abcdefg",
    confirmation_passowrd: "abcdefg"
}
Enter fullscreen mode Exit fullscreen mode

4. Time format

It should return times in UTC formatted to ISO8601.

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

For example

{
    "created_at": "2021-01-21T15:23:38Z"
}
Enter fullscreen mode Exit fullscreen mode

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

The status code for HTTP should be 404

{
    type: "account_not_found",
    message: "The account is not existing"
}
Enter fullscreen mode Exit fullscreen mode

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

GET /v1/customers?page=2&per_page=30
Enter fullscreen mode Exit fullscreen mode

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 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 and Swagger Examples for more details.

Discussion (0)

pic
Editor guide