22 Best Practices to Take Your API Design Skills to the Next Level

Practical advice for designing REST APIs

Ever got frustrated with a horrible API where everything’s a guessing game? Well, I have.

In this world of microservices, a consistent design for your backend API is imperative.

Today, we’ll talk about some best practices to follow. We’ll keep it short and sweet — so buckle up!

First, Some Terminology

Any API design follows something called Resource Oriented Design It consists of three key concepts

Resource: A resource is a piece of data, For example, a User. Collection: A group of resources is called a collection. Example: A list of users. URL: Identifies the location of resource or collection. Example: /user

1. Use kebab-case for URLs

For example, if you want to get the list of orders.

Bad:

/systemOrders or /system_orders

Good:

/system-orders

2. Use camelCase for Parameters

For example, if you want to get products from a particular shop.

Bad:

/system-orders/{order_id} or /system-orders/{OrderId}

Good:

/system-orders/{orderId}

3. Plural Name to Point to a Collection

If you want to get all the users of a system.

Bad:

GET /user or GET /User

Good:

GET /users

4. URL Starts With a Collection and Ends With an Identifier

If want to keep the concept singular and consistent.

Bad:

GET /shops/:shopId/category/:categoryId/price

This is bad because it’s pointing to a property instead of a resource.

Good:

GET /shops/:shopId/ or GET /category/:categoryId

5. Keep Verbs Out of Your Resource URL

Don’t use verbs to express your intention in the URL. Instead, use proper HTTP methods to describe the operation.

Bad:

POST /updateuser/{userId} or GET /getusers

Good:

PUT /user/{userId}

6. Use Verbs for Non-Resource URL

You have an endpoint that returns nothing but an operation. In this case, you can use verbs. For example, if you want to resend the alert to a user.

Good:

POST /alerts/245743/resend

Keep in mind that these are not our CRUD operations. Rather, these are considered functions that do a specific job in our system.

7. Use camelCase for JSON property

If you’re building a system in which the request body or response is JSON, the property names should be in camelCase

Bad:

{
   user_name: "Mohammad Faisal"
   user_id: "1"
}

Good:

{
   userName: "Mohammad Faisal"
   userId: "1"
}

8. Monitoring

RESTful HTTP services MUST implement the /health and /version and /metrics API endpoints. They will provide the following info.

/health Respond to requests to /health with a 200 OK status code.

/version Respond to request to /version with the version number.

/metrics This endpoint will provide various metrics like average response time.

/debug and /status endpoints are also highly recommended.

9. Don’t Use table_name for the Resource Name

Don’t just use the table name as your resource name. In the long run, this kind of laziness can be harmful.

Bad: product_order

Good: product-orders

This is because exposing the underlying architecture is not your purpose.

10. Use API Design Tools

There are many good API design tools for good documentation, such as:

  • API Blueprint
  • Swagger

Having good and detailed documentation results in a great user experience for your API consumers.

11. Use Simple Ordinal Number as Version

Always use versioning for the API and move it all the way to the left so that it has the highest scope. The version number should be v1, v2 etc.

Good:

http://api.domain.com/v1/shops/3/products

Always use versioning in your API because if the API is being used by external entities, changing the endpoint can break their functionality.

12. Include Total Number of Resources in Your Response

If an API returns a list of objects always include the total number of resources in the response. You can use the total property for this.

Bad:

{
  users: [
     ...
  ]
}

Good:

{
  users: [
     ...
  ],
  total: 34
}

13. Accept limit and offset Parameters

Always accept limit and offset parameters in GET operations.

Good:

GET /shops?offset=5&limit=5

This is because it’s necessary for pagination on the front end.

14. Take fields Query Parameter

The amount of data being returned should also be taken into consideration. Add a fields parameter to expose only the required fields from your API.

Example: Only return the name, address, and contact of the shops.

GET /shops?fields=id,name,address,contact

It also helps to reduce the response size in some cases.

15. Don’t Pass Authentication Tokens in URL

This is a very bad practice because often URLs are logged and the authentication token will also be logged unnecessarily.

Bad:

GET /shops/123?token=some_kind_of_authenticaiton_token

Good: Instead, pass them with the header:

Authorization: Bearer xxxxxx, Extra yyyyy

Also, authorization tokens should be short-lived

16. Validate the Content-Type

The server should not assume the content type. For example, if you accept application/x-www-form-urlencoded then an attacker can create a form and trigger a simple POST request.

So, always validate the content-type and if you want to go with a default one use content-type: application/json

17. Use HTTP Methods for CRUD Functions

HTTP methods serve the purpose of explaining CRUD functionality.

GET: To retrieve a representation of a resource.

POST: To create new resources and sub-resources.

PUT: To update existing resources.

PATCH: To update existing resources. It only updates the fields that were supplied, leaving the others alone

DELETE: To delete existing resources.

18. Use the Relation in the URL For Nested Resources

Some practical examples are:

GET /shops/2/products : Get the list of all products from shop 2. GET /shops/2/products/31: Get the details of product 31, which belongs to shop 2. DELETE /shops/2/products/31 , should delete product 31, which belongs to shop 2. PUT /shops/2/products/31 , should update the info of product 31, Use PUT on resource-URL only, not the collection. POST /shops , should create a new shop and return the details of the new shop created. Use POST on collection-URLs.

19. CORS

Do support CORS (Cross-Origin Resource Sharing) headers for all public-facing APIs.

Consider supporting a CORS allowed origin of “*”, and enforcing authorization through valid OAuth tokens.

Avoid combining user credentials with origin validation.

20. Security

Enforce HTTPS (TLS-encrypted) across all endpoints, resources, and services.

Enforce and require HTTPS for all callback URLs, push notification endpoints, and webhooks.

21. Errors

Errors, or more specifically service errors, occur when a client makes an invalid or incorrect request to a service or passes invalid or incorrect data to a service, and the service rejects the request.

Examples include invalid authentication credentials, incorrect parameters, unknown version IDs, etc.

Do return 4xx HTTP error codes when rejecting a client request due to one or more Service Errors. Consider processing all attributes and then returning multiple validation problems in a single response.

22. Golden Rules

If you are ever in doubt about an API formatting decision, these golden rules can help guide us to making the right decision.

  • Flat is better than nested.
  • Simple is better than complex.
  • Strings are better than numbers.
  • Consistency is better than customization.

That’s it — congratulations if you’ve made it this far! I hope you learned a thing or two.

I hope you have a great day!


Share this post


Read more articles...

team

How to Design a Clean Database

Profile Image

Who I am

Hi, I amMohammad Faisal, A full-stack software engineer @Cruise , working remotely from a small but beautiful country named Bangladesh.

I am most experienced inReactJS,NodeJS andAWS

Buy Me a Coffee Widget