API

Best Practices 


Design and Documentation

Use RESTful Principles:

  • Follow REST principles to create predictable and standard APIs.
  • Use appropriate HTTP methods like: GET: To receive any data from the server POST: To save any data to the server PUT: To update a particular record DELETE: To delete the record PATCH: for partial update 

Consistent Naming Conventions:

  • Use clear and consistent naming conventions for endpoints.
  • API Url should be user-friendly & module specific. Below is the example for the Product module: GET https://your-domain/v1/product
  • POST https://your-domain/v1/product/

    Get Product details https://your-domain/v1/product/201

    PUT https://your-domain/v1/product/201/

    PATCH https://your-domain/v1/product/201

    DELETE https://your-domain/v1/product/201

  • Use a hyphen for the URL if two words need to be combined. (Camel case looks ugly in URL)
  • IDs should be encrypted – One should not be able to guess them. We can use UUID.
  • Need to get URLs reviewed – Sr Dev or Testers(No spelling mistakes)

Versioning:

  • Versioning your API is mandatory to manage changes without breaking existing clients.
  • If your API is live and there are major changes in API, then create the same API with different versions so the existing users will not get affected.
  • Your new API URL will be like https://your-domain/v2/api/users
  • Your old API URL will be like https://your-domain/v1/api/users

Documentation:

  • Provide comprehensive and clear documentation using tools like Swagger.
  • Include Description, Examples, Error codes, Dummy Requests, and Responses with a description for each endpoint.

Environment:

  • Your API must have a staging and production environment.

 

Data Types

  • Don’t use null for the value of any key. Use 0 for integers Use false for booleans Use “” for strings Need to have a default value from the database to avoid problems.
  • It is good to use a boolean or number data type if your response has that type of value.
{"first_name":"Jon","last_name":"Doe","age":31,"is_admin":false}
  • If you are returning a single entity then only use the object, else array of objects.
//For login user details:// Correct"user_details": { "first_name": "Jon", "last_name": "Doe", "age": 31, "is_admin": false}// Wrong"user_details": [ { "first_name": "Jon", "last_name": "Doe", "age": 31, "is_admin": false }]

 

Request and Response best practices

Authentication and Authorization:

  • Use JWT or OAuth 2.0 Security for authentication.
  • Ensure proper authorization checks for every API call.
  • JWT Token needs to be passed in all the web services except login, and it should be passed in the header instead of the parameter.
  • Authorization token (JWT) passed in Authorization key with Bearer Prefix in JWT token. Ex: Authorization: Bearer eyJhbGciOiJIUOk6yJV_adQssw5c

HTTPS:

  • Always use HTTPS to encrypt data in transit.

Request Parameters:

  • Validate all incoming data to prevent injection attacks.
  • Use libraries like Joi,Yup or Valibot for validation.
  • Naming conventions: all small case words should be separated using an underscore.
  • Use JSON type for the request body. Use form-data only when image upload is required.
  • Images need to pass in form-data
  • Special characters and emojis need to be converted to UTF-8.

Response Parameters:

  • API response should be in JSON format. (Note. A plain JSON string is not JSON data). The header should be application/JSON.

 

Security

Rate Limiting:

  • You must have to use the API rate limiter package to prevent a large number of API requests from a single system in a minute.
  • The first preference is the rate limiter package second is a web server and if you are using an API gateway then you can manage through it.
  • You must have to use the helmet package for API security

 

Performance

Pagination and Filtering:

  • Implement pagination for endpoints returning large datasets.
  • Allow filtering, sorting, and searching capabilities.

Asynchronous Processing:

  • Heavy tasks should be handled through background jobs using tools like Bull, RabbitMQ, or AWS SQS.

Optimization:

  • 95% API must be responded in a second (THIS IS A THUMB RULE FOR ALL)
  • Optimize database queries and indexing.

Caching:

  • Use caching mechanisms (e.g., HTTP caching, Redis) to reduce load and improve performance.
  • Implement appropriate cache headers.
  • When making the same API request to the NGINX server then it does not need to forward this request. The NGINX server will simply respond right away to the client with the saved response from before. This will result in less work for the web server, and faster response time.
  • You need to make the below change in the Nginx configuration file
# In /etc/nginx/sites-available/default# caching pathproxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cache:10m inactive=60m;server { listen 8000 default_server; listen [::]:8000 default_server; server_name _; # ONLY IDEMPOTENT URI IS CACHED location ~ /read/(.*)+/(.*)$ { proxy_pass http://example.com; proxy_cache cache; proxy_cache_valid any 10m; add_header X-Proxy-Cache $upstream_cache_status; } # The rest of the request is passed (will not be cached) location / { proxy_pass http://example.com; } }

 

Error Handling

  • For an API, all use cases (validation, data not found, internal error, success, access denied(not login)) will be managed by HTTP response code. (a) 200 => Success (b) 201 => Created (c) 404 => Not found (d) 422 => Bad request or validation error message (e) 409 => already exist (f) 500 => internal server error (Catch block of try/catch) (g) 401 => Unauthorized access denied. (h) 403 => Forbidden, The client does not have access rights to the content
  • Don’t use custom code like success:1 or success:0 until not required.
  • error_code should be defined when there are multiple scenarios for a single HTTP error code.
  • ‘message’ should be the key for all error and success messages.
  • The data parameter should be there for all successful responses. In case there is no data to send then send a blank object.

 

{ status: true, message : “fetched data successfully.”, Data : [{}, {}....]}

0