Best practices for web API design

Laptop on a table in a coffee shop with a screen that says API's

A coffee‑shop‑inspired tutorial on API design best practices

Designing a good API is a lot like running a smooth, friendly and efficient coffee shop. Customers show up with requests, you deliver the right payload (drink) and everyone leaves satisfied, ideally wanting to come back for more.

Definition of an application programming interface (API)

An API constitutes a set of defined rules and protocols that enable different software applications to communicate and interact with each other. It functions as an intermediary layer, abstracting the underlying complexities of a system while exposing only the specific functionalities and data needed by another system to consume. APIs delineate the methods and data formats that applications can use to request and exchange information in a consistent and reliable way.

Let’s walk through some API design best practices by using our fictional café; “RESTful Roast,” as the setting.

Understand your API’s purpose: The coffee shop’s use cases

By understanding your API’s purpose, it will inform the API design. This really matters for a bunch of reasons. When an API is designed well, developers have a smoother time working with it. Integrations become easier, faster and far less frustrating, which saves everyone time and money. 

A solid API also helps different systems play nicely together, so applications can share information without hiccups. Good API design also sets you up for the future: it can scale, evolve and grow without breaking what’s already working. Strong design is also key for security as it creates clear rules about who can access what, and how, so your data stays protected.

Coming to our fictional example, before our café even opens, we need clear use cases identified:

  • Order coffee
  • Browse the menu
  • Manage loyalty accounts

In API terms, these become endpoints mapped to specific customer actions. Thoughtful system design ensures that each action is handled by the right server‑side functions.

REST API basics: The shop layout

REST (Representational State Transfer) is crucial to cover first as it’s the de facto internet standard for API development and will help solidify our coffee shop example into an openAPI specification. It defines constraints for a simple, scalable and reliable distributed system. Key characteristics include statelessness, client/server separation, cacheability and a uniform interface.

REST API is like the physical layout of the café, organized, intuitive and designed for flow.

Key pieces of a REST API:

  • Resources : items available in the shop
  • HTTP methods : actions a customer takes
  • Schema : consistent structure for what’s on the menu
  • Header and authentication : your café loyalty card or ID
  • Query parameters : “extra espresso shot?”
  • HTTP status codes : clear responses (“Order received,” “Out of stock,” “Invalid coupon”)

Everything should help the customer (or client application) clearly understand what’s happening.

Resource-oriented design

Resource-oriented design is fundamental to how REST APIs work. In this paradigm, everything is considered to be a resource, and these resources are identifiable by unique Uniform Resource Identifiers (URIs). For example, a “menu” or an “order” would be a resource. URIs should be clear, hierarchical and indicative of the resource they represent. 

Nouns, preferably plural, are used in URIs to denote collections, such as `menu/items ` or `orders `. The focus is on the resources themselves, rather than on actions or verbs, which are implicitly handled by HTTP methods.

Mapping customer actions to HTTP methods

The appropriate use of HTTP methods is critical for adherence to REST principles. Each standard HTTP method has a well-defined semantic purpose:

  • GET: Retrieves a representation of a resource or a collection of resources. GET requests should be idempotent and safe, meaning they do not alter the server’s state.
  • POST: Creates a new resource within a collection. POST requests are not idempotent.
  • PUT: Updates an existing resource completely or creates a resource if it does not exist at the specified URI. PUT requests are idempotent.
  • PATCH: Partially updates an existing resource. PATCH requests are not necessarily idempotent.
  • DELETE: Removes a resource. DELETE requests are idempotent. Proper application of these methods enhances predictability and uses the existing semantics of the HTTP protocol.

At RESTful Roast, you don’t let customers reorganize the furniture to place an order. Similarly, APIs shouldn’t misuse verbs and follow the appropriate HTTP method. Here are some examples: 

  • GET : A customer reads the menu.
  • POST : A customer places a new order (creates a resource).
  • PUT/PATCH : A customer updates their loyalty profile.
  • DELETE : A customer cancels an order.

Using the right verbs keeps your API maintainable and predictable.

Designing your endpoints: Clear and consistent (like a good menu)

Consistency in API design refers to the uniform application of naming conventions, data formats, error structures and behavioral patterns across all endpoints and resources. 

For example, if an API uses `data ` wrapper to identify a successful request regardless of resource and an `error ` wrapper when an error occurs then it reduces cognitive load for developers. This clarity makes the API easier to learn, understand and use effectively. Inconsistency can lead to confusion, errors and increased integration time. 

Predictability in API design means that the API’s behavior should be intuitive and conform to user expectations based on its design patterns and documentation. When a client sends a request to a particular endpoint with specific parameters, the expected response structure and content should be consistent every time, assuming valid input and system state. 

For instance, a GET request to a resource collection should always return a list of resources, and a POST request to the same collection should always attempt to create a new resource. This predictability fosters trust and simplifies client-side implementation.

Ordering in the café uses simple methods to place an order, get the status of an order and your API should follow the same clarity:

GET /orders → returns a list of orders

POST /orders → creates a new order

GET /orders/{orderId} → returns a single order

POST /orders -> returns a 201 with the newly created order 

Request body and response body: The order ticket system

When a customer places an order:

  • The request body is the order slip (“latte,” “medium,” “oat milk”).
  • The response body is the confirmation (“Order #123 will be ready in 5 mins”).

A consistent schema ensures every barista (your backend service) interprets requests the same way. And just like a café needs clear communication at the counter, APIs rely on HTTP status codes to tell customers exactly what’s going on.

Status codes are standardized and reviewed by the IETF and the specifications can be found on the official HTTP documentation site

Here is a RESTful Roast inspired version of each status code class to help explain when you would use what type of status code. 

Informational Responses ( 100 - 199 )

1XX response messages are used for indicating that a request was received, understood and is being processed in some way. They alert a client to wait for a final response. They do not contain a body.

Status CodeExample Use
100 ContinueWe got your order, just grinding the beans now.

Successful Responses ( 200 - 299 )

2XX response messages means the request succeeded and the meaning of success will depend on the HTTP method that was used in the request, whether its aGET ,PUT ,POST etc. Some of the most common status codes are below.

Status CodeExample Use
200 OKYour drink is ready,enjoy!
201 CreatedYour custom order has been created and added to the queue.
204 No ContentOrder completed, nothing response provided

Redirection Messages ( 300 - 399 )

3xx response messages tells the client that they must take additional action, the most common being redirection of a request. 

Status CodeExample Use
301 Moved PermanentlyEspresso orders are now picked up at the new station.
302 FoundWe’re redirecting you to the barista on shift

Client Error Responses ( 400 - 499 )

4xx response messages are for situations when there was an error caused by the client making the request, i.e the customer’s request isn’t quite right. Some of the most common types of these errors are described below.

Status CodeExample Use
400 Bad Request 
We can’t make a latte if you don’t provide information on milk 
401 UnauthorizedYou need to provide your name if we are going to make you a coffee
403 ForbiddenOnly specific loyalty members can order that
404 Not FoundThat isn’t a drink we make 
429 Too Many RequestsYou are trying to place the order too many times, that doesn’t seem right

Server Error Responses ( 500 - 599 )

5xx response messages are used where the server has encountered an error and is incapable of fulfilling the request. Think of this as the café not being able to provide the service they would expect they can. The following are the 2 most common types of these response messages.

Status CodeExample Use
500 Internal Server ErrorOur espresso machine is broken and we can’t take your order
503 Service UnavailableWe’re temporarily closed 

Validation: Don’t serve a mocha without coffee

APIs should validate all inputs, just like your café double checks that an order makes sense before the barista starts pulling shots.

Some classic examples:

  • No negative quantities
  • No sending both “milk” and “no milk”
  • Only valid menu items allowed

Good validation keeps systems running smoothly. It gives developers fast, clear feedback and prevents your backend from becoming a chaotic stream of server errors caused by invalid requests.

Where OpenAPI (especially OpenAPI 3.0) really shines is in helping you define and enforce these rules. With an OpenAPI specification, you can describe your request and response schemas in detail, everything from required fields, to allowed values, to data types, to enum lists for items on the “menu.” That means:

  • Clients can catch mistakes before sending a request (like trying to order a “Triple‑Pumpkin‑Spicy‑Mocha” that doesn’t exist).
  • IDEs and API tools can auto‑validate requests while developers type.
  • API gateways and middleware can automatically reject invalid orders without touching your backend.
  • The documentation stays perfectly in sync with what the API expects—no stale menu boards.

It’s like handing customers a beautifully printed menu where impossible drinks simply do not appear, making it easier for everyone to get their order right on the first try.

Caching: The “daily specials” board

Some information rarely changes, like:

  • The menu
  • Store hours
  • Popular items

You can cache these responses, just like posting daily specials on a chalkboard. This reduces load and speeds up service for your client application.

Caching is a technique used to store copies of frequently accessed data in a temporary storage location (a cache) so that future requests for that data can be served more quickly. For APIs, caching can significantly improve performance, reduce latency, and decrease the load on backend servers.

  • Client-side caching: Using HTTP caching headers like `Cache-Control `, `Expires ` and `ETag ` to instruct client applications and intermediate proxies on how long to cache responses.
  • Server-side caching: Implementing caches at various layers within the API’s infrastructure (for example, database query caches, object caches, CDN caches) to store frequently requested data.
  • Proxy caching: Uses reverse proxies or content delivery networks (CDNs) to cache API responses closer to the client, reducing latency and bandwidth usage. Effective caching strategies consider data freshness, cache invalidation mechanisms and appropriate cache durations for different types of resources.

Pagination: One page of the menu at a time

Imagine a massive list of every item and customization that a coffee shop could make. Customers would walk out. Using pages to put items when there a lot of them makes a lot more sense. 

APIs also need pagination for large datasets:

/orders?page=2&limit=20

When dealing with large datasets, returning all records in a single API response is inefficient and can lead to performance issues and excessive network usage. Paging and filtering mechanisms address these issues: 

Paging divides large result sets into smaller, manageable chunks. Common methods include: 

  • Offset-based paging: Using `limit ` and `offset ` parameters (for example, `/items?limit=10&offset=20 `). This method is simple but can be inefficient for very deep pages.
  • Cursor-based paging: Using a pointer to the last item retrieved in the previous request (for example, `/items?cursor=eyJpZCI6MTIzfQ== `). This method is more efficient for large datasets and avoids issues with data changes during pagination.

Filtering allows clients to narrow down results based on specific criteria. This filtering is typically done through query parameters, to filter for pastries that cost less than $5.00 could be something like `/products?category=pastries&price_lt=500 `).

The API should support a range of filtering operators (for example, equals, greater than, less than, contains).

This capability keeps responses fast, readable and manageable.

API versions: Seasonal menus

Sometimes you add new features, rename items or retire old ones.

That situation is where API versions come in:

/v1/orders

/v2/orders

Versioning APIs is a crucial practice for managing changes and ensuring compatibility with earlier versions as an API evolves. When breaking changes are introduced, a new version of the API should be released. Common versioning strategies include:

  • URI versioning: Embedding the version number directly into the URI (for example, /v1/users ). This method is straightforward and highly visible.
  • Header versioning: Including the version number in a custom HTTP header (for example, X-API-Version: 1 ). This method keeps URIs clean but might be less intuitive for initial discovery.
  • Content negotiation versioning: Using the Accept header to specify the desired media type and version (for example, Accept: application/vnd.example.v1+json ). This method leverages HTTP’s built-in content negotiation mechanism. Each strategy has its advantages and disadvantages, and the choice depends on the specific API’s needs and development philosophy.

This practice ensures compatibility with an earlier version so loyal customers aren’t forced into a new menu unexpectedly.

Authentication and API keys: The loyalty program

Just like certain perks require a membership card (or API keys), your API should require authentication for things like:

  • Personal account information
  • Order history
  • Payment methods

Authentication is the process of verifying the identity of a client attempting to access an API. Common authentication mechanisms include:

  • API keys: Simple tokens provided in headers or query parameters for identifying clients, suitable for public APIs with rate limiting.
  • OAuth 2.0: An authorization framework that allows third-party applications to obtain limited access to a user’s resources on an HTTP service, acting on behalf of the user. It delegates user authentication to the service that hosts the user account.
  • JSON Web Tokens (JWT): A compact, URL-safe means of representing claims to be transferred between two parties. JWTs are often used as bearer tokens after successful authentication.
  • Basic authentication: Username and password are encoded in Base64 and sent in the HTTP Authorization header. Less secure without TLS. The chosen mechanism should align with the API’s sensitivity and target audience.

Also, you wouldn’t want everyone who accesses the API to add or remove items from a menu or update payment methods. Authorization helps determine what a client can do once their identity has been verified. Effective authorization strategies involve:

  • Role-based access control (RBAC): Assigning permissions to roles and then assigning roles to users. For example, an “admin” role might have full access, while a “viewer” role has read-only access.
  • Attribute-based access control (ABAC): Granting access based on attributes of the user, resource or environment. This offers more fine-grained control than RBAC.
  • Scope-based authorization: Commonly used with OAuth 2.0, where access tokens are granted with specific “scopes” (for example, read_profile, write_data) that limit the actions the client can perform. Proper authorization ensures that clients can access and manipulate only data for which they have explicit permission, enforcing the principle of least privilege.

OpenAPI specification, Swagger and docs: Your barista handbook

Your staff doesn’t memorize everything, they likely rely on a well-written handbook. Good API Design involves focusing on documentation too. 

Tools like:

Help you provide detailed API documentation so developers can understand:

  • Endpoints
  • Expected request and response bodies
  • Authentication
  • Error codes
  • Examples

Comprehensive API documentation is indispensable for the adoption and successful integration of an API. It serves as the primary resource for developers, explaining how to interact with the API, what data formats to expect and how to handle various scenarios. Effective documentation should include:

  • Overview and getting started guides: Basic setup and authentication instructions.
  • Endpoint descriptions: Detailed explanations of each resource, supported HTTP methods, request parameters and response structures (including examples).
  •  Error codes and messages: A complete list of possible error responses and their meanings.
  • Authentication and authorization details: Clear instructions on how to authenticate and authorize requests.
  • Rate limits and usage policies: Information on API usage restrictions.
  • SDKs and libraries: Links to available client libraries. Tools like OpenAPI (formerly Swagger) allow for machine-readable API specifications that can generate interactive documentation portals, improving discoverability and usability.

Remember, great docs equal great developer experience.

Debugging: When the espresso machine breaks

Just like baristas troubleshoot equipment issues, APIs need good debugging tools:

  • Clear error messages
  • Trace IDs in logs
  • Structured JSON/XML errors

This reduces time spent fixing issues and improves reliability. Robust error handling is a cornerstone of a well-designed API. When an error occurs, the API should return a meaningful HTTP status code along with a consistent, structured error response body. This response body typically includes:

  • An error or errors field.
  • A code that uniquely identifies the error type (for example,INVALID_INPUTRESOURCE_NOT_FOUND ).
  • A human-readable message explaining the error.

Optionally, details or fields indicating specific problematic parameters. Consistent error structures enable client applications to parse and handle errors programmatically, improving the overall reliability and user experience. Avoid generic error messages like “An unknown error occurred.

RPC, GraphQL and other types of APIs: Alternative café styles

While REST is your main café layout in our example, other formats for APIs do exist. Here is a high-level analogy for each type:

  • RPC (Remote Procedure Call)—an express counter: tell the barista exactly what to do (“makeLatteNow”).
  • GraphQL—a customizable menu: clients choose exactly the data that they want. E.g all Non milk drink options
  • Web API—a general-purpose service for web applications.
  • XML support—for customers with legacy order forms.

Use each approach based on your customer’s needs.

Idempotency: Don’t make two lattes for one order

If a customer taps the card reader twice, you don’t make two drinks. 

Similarly, idempotent methods like PUT  and DELETE  must behave the same no matter how many times they’re called. This prevents duplicate charges or unnecessary resource creation.

Microservices: Specialized counters in the café

Imagine that your café has become so popular that you don’t take all requests at the main counter any longer and have separate stations for different items that require different types of ingredients and approaches to service requests. For example:

  • Espresso bar
  • Bakery
  • Cold brew lab

microservices architecture works the same way, independent services handling distinct responsibilities.

API design best practices summary

A well-designed API should be:

  • Clear
  • Predictable
  • Maintainable
  • Well-documented
  • Compatible with earlier versions
  • Consistent in request and response structure
  • Secure with strong authentication
  • Efficient through caching and pagination

Just like a perfectly run coffee shop.

If your API (café) is clean, organized and delightful to interact with, developers will keep coming back—loyal customers for life.

Author

Ash Minhas

Manager, Technical Content | AI Advocate

IBM

Related solutions
IBM API Connect

Easily create, manage, and secure APIs with IBM API Connect®.

Explore IBM API Connect
IBM integration software and solutions

Unlock business potential with IBM integration solutions, which connect applications and systems to access critical data quickly and securely.

Explore IBM integration solutions
Cloud Consulting Services

Harness hybrid cloud to its fullest value in the era of agentic AI

Explore cloud consulting services
Take the next step

Discover how IBM API Connect® accelerates API design, enhances security, and streamlines integration to improve reliability while reducing development time.

  1. Discover IBM API Connect
  2. Explore IBM integration solutions