Aetherio Logo

Designing a Good REST API: Best Practices, Common Mistakes, and Concrete Examples

12 minutes mins to read

Share article

Introduction

In today's digital landscape, businesses increasingly rely on interconnected solutions. APIs (Application Programming Interfaces) are the glue that holds this interconnection together, allowing different applications to communicate smoothly and efficiently. Among the various API architectural styles, the REST API (Representational State Transfer) has become an essential standard, praised for its simplicity, scalability, and flexibility. However, "doing REST" isn't enough; designing a good REST API that is robust, performant, and easy to use requires mastering fundamental principles and proven best practices.

At Aetherio, our expertise in custom application development has shown us that the quality of an application often depends on the robustness of its APIs. A poorly designed API can lead to developer headaches, performance issues, security vulnerabilities, and exorbitant maintenance costs. This article, born from our experience on critical projects for clients like Worldline and Adequasys, will guide you through the essential principles of REST API design, addressing common mistakes to avoid and providing concrete examples to build interfaces worthy of 2025 standards.

REST API Design

Fundamentals of REST API Design: Naming and Resources

A well-designed REST API begins with properly modeling its resources—the entities (users, products, orders) that your API exposes. Naming endpoints is crucial for the readability and intuitiveness of your interface. A clear URL should allow a developer to understand what it represents without needing to consult the documentation. The idea is to remain true to the REST principle of manipulating identifiable resources.

Intuitive URLs: Resources, Not Actions

Your API URLs should represent resources, not actions. Avoid verbs in your URLs. For example, instead of /getAllUsers or /createNewProduct, use plural nouns for resources. This reflects the idea that you are manipulating a collection of resources or a specific resource within that collection.

  • Best Practices:
    • Plural resource names: /users, /products, /orders
    • Clear hierarchy for nested resources: /users/{id}/orders for orders belonging to a specific user.
    • Use ID for specific resources: /users/{id}, /products/{id}
  • Examples:
    • GET /users: Retrieves a list of all users.
    • GET /products/123: Retrieves the product with ID 123.
    • POST /orders: Creates a new order.
    • GET /users/456/orders: Retrieves orders for user ID 456.

The use of /users/{id}/orders perfectly illustrates how to structure relationships between resources. Each segment of the URL represents a resource, and the hierarchy is explicit. This not only aids understanding but also helps with the scalability and maintainability of your API.

Correct Use of HTTP Verbs

HTTP verbs (or HTTP methods) are fundamental for indicating the desired action on a resource. Each verb has precise semantics that must be respected. This is one of the pillars of REST API design. Inappropriate use can create confusion and make the API difficult to interoperate with.

  • GET : Data Retrieval (Idempotent)
    • Used to read or retrieve a resource. Multiple GET requests for the same resource should always return the same state, with no side effects on the server. Example: GET /products/123
  • POST : Creating New Resources
    • Used to create a new resource. Typically, the request body contains the data of the resource to be created. Example: POST /products (with new product data in the body).
  • PUT : Complete Replacement of a Resource (Idempotent)
    • Used to update an existing resource by completely replacing its content. If the resource does not exist, PUT may create it. Multiple PUT requests with the same body should leave the resource in the same final state. Example: PUT /products/123 (with all updated product data).
  • PATCH : Partial Modification of a Resource
    • Used to apply partial modifications to an existing resource. Only the fields to be modified are sent in the request body. This is often more efficient than PUT for minor updates. Example: PATCH /products/123 (with only the updated price).
  • DELETE : Deleting a Resource (Idempotent)
    • Used to delete a specific resource. Multiple DELETE requests for the same resource (if it was deleted after the first one) should not have additional side effects. Example: DELETE /products/123

Respecting these conventions makes your API predictable and easy for consumers to integrate. This is a hallmark of technical excellence that we prioritize at Aetherio for all application development with robust APIs.

Handling Responses: HTTP Status Codes and Error Management

Communication isn't just about sending requests. How your API responds, especially in cases of success or failure, is equally important. Standardized HTTP status codes are your best ally here.

HTTP Status Codes: A Universal Language

HTTP status codes provide a standardized way to indicate the result of an HTTP request. Ignoring them or using them inconsistently is a fundamental mistake that will make your API opaque.

  • 2xx Series (Success):
    • 200 OK: The request was successfully processed. The response typically contains the requested data.
    • 201 Created: A new resource was successfully created. Used after a POST. The response should include the URL of the new resource (in the Location header) and potentially the resource itself.
    • 204 No Content: The request was successfully processed, but there's no content to return. Often used for DELETE or PUT requests where success is sufficient without returning data.
  • 4xx Series (Client Errors):
    • 400 Bad Request: The request is malformed (incorrect syntax, invalid payload). Error due to the client.
    • 401 Unauthorized: Authentication is required or failed. The client did not provide valid credentials. (Different from 403!). Learn more about API security and authentication.
    • 403 Forbidden: The client is authenticated but does not have the necessary permissions to access the resource. The server refuses authorization.
    • 404 Not Found: The requested resource does not exist or cannot be found.
    • 405 Method Not Allowed: The HTTP method used is not allowed for this resource (e.g., PUT on a resource that only supports GET).
    • 422 Unprocessable Entity: The request is semantically incorrect (e.g., data validation fails). Often used for validation errors of submitted fields.
    • 429 Too Many Requests: The client has sent too many requests in a given time frame (rate limiting).
  • 5xx Series (Server Errors):
    • 500 Internal Server Error: An unexpected error occurred on the server. Generic error, to be refined if possible.
    • 503 Service Unavailable: The server is not ready to handle the request (overload, maintenance).

Error Handling: Clarity and Standardization

When errors occur, your API must not only return the correct HTTP status code but also a structured and informative response body. Error responses should be consistent to facilitate debugging and integration.

  • Best Practices:
    • Standardized format: Use a common format (e.g., JSON) for all error responses.
    • Key information: Include an application-specific error code, a human-readable message for the developer, and potentially additional details (invalid fields for a 422).
    • Human message + machine code: The message should be understandable by a human, the machine code should be usable for programmatic logic.
  • Example of a 422 Unprocessable Entity error response: