top of page
  • Linkedin
  • Twitter

API Design Guidelines




A collection of API design guidelines and insights provided by many across the community.


What is an API

As per Wikipedia: An Application Programming Interface (API) is a specification intended to be used as an interface by software components to communicate with each other.


What is REST

REST is a set of principles that define how Web standards, such as HTTP and URIs, are supposed to be used (which often differs quite a bit from what many people actually do). REST stands for Representational State Transfer, and was first described in chapter 5 of Roy Fielding's Ph.D dissertation


REST Architectural Constraints defined by Wikipedia

  • Client-Server: A uniform interface separates clients from servers. This separation of concerns means that, for example, clients are not concerned with data storage, which remains internal to each server, so that the portability of client code is improved. Servers are not concerned with the user interface or user state, so that servers can be simpler and more scalable

  • Stateless: This means is that the necessary state to handle the request is contained within the request itself, whether as part of the URI, query-string parameters, body, or headers

  • Cacheable: Responses must implicitly or explicitly, define themselves as cacheable, or not, to prevent clients reusing stale or inappropriate data in response to further requests.

  • Layered System: A client cannot ordinarily tell whether it is connected directly to the end server, or to an intermediary along the way.

  • Uniform Interface: The uniform interface constraint defines the interface between clients and servers. It simplifies and decouples the architecture, which enables each part to evolve independently.

  • Code on demand (Optional): Servers can temporarily extend or customise the functionality of a client by the transfer of executable code.


REST principles adopted by RESTful APIs

  • Expose 'Resources' to represent important concepts and objects

  • Ensure each resource is uniquely 'addressable' via a URI, so that clients may interact with them over HTTP

  • Provide 'representations' (e.g., using JSON and or XML) of those resources

  • Provide a consistent interface based upon the standard HTTP methods

  • Ensure interaction with the API is stateless in nature, in order to provide flexibility in deployment as well as to promote scalability


RESTful vs REST

The difference between REST and RESTful is simply semantics. REST is an architectural style applied to a client-server relationship. RESTful is simply a way of telling your clients that you use REST. RESTful API should conform to REST constraints defined above.

Martin Fowler authored a very nice overview of the Richardson Maturity Model used for gauging an API's 'level of RESTfulness'. This seems to be the most popular maturity model for REST.


What makes a good RESTful API

Follows Robustness principle which says “Follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others."

  • An API is a developer's UI - just like any UI, it's important to ensure the user's experience is thought out carefully

  • An API is only as good as its documentation. The documents should be easy to find and publically accessible

  • Provides support for backward compatibility or versioning

  • Does not expose internal domain object structures or database entity as resource representations


API Design Guidelines

Expose Meaningful Resources for API

“The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource. As per Roy Fielding’s dissertation, "A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.


It is very important to select the right resources and model the resources at the right granularity while designing the REST API so that the API consumers get the desired functionality from the APIs, the APIs behave correctly and the APIs are maintainable.

Identifying the resources to expose, and the content of those resources, is an iterative process and requires feedback. It is also important not to allow one client to drive the API design at the expense of other clients (if they are also known), or to deviate from common API practices or this strategy. APIs are basically a "business layer" or middleware application tier. APIs should either encapsulate business operations or, in the ever-more-popular REST style, application resources.


Use a consistent representation

Defining representations includes selection of the properties to be expressed, selecting appropriate attribute and element names, defining the structure (including hierarchical structures. Mike Amundsen identifies three primary styles for representing domains: 'domain-specific', 'general', and 'agnostic'.

Domain Style

Description

general

General element names are used whenever possible (and these are then decorated with attributes to provide the specificity). Example element: "loan": {"type":"auto }

domain-specific

Closely models the domain with respect to element names and structure. Example element: "auto-loan"

agnostic

Uses generic element names and relies on attributes to provide context. Example element: "ul": {"type":"auto-loan" }

Fine Grained Resources vs Coarse Grained Resources

If we design the API around fine-grained resources, we would end up with a chattier API for consumer applications. On the other hand, if we design the API based on very coarse-grained resources (designed to do everything) there will not be enough variations to support all the API consumers’ needs and the API may become too difficult to use and maintain.


There may be situations where an API that is built around low-level resources may just be fine. For example, to get bank account balance information, an API that is built around “Account” resource is good enough. On the other hand, if the need is to do a money transfer or to get a bank statement, the API needs to be built around the coarse-grained “Transactions” resource. Service designer should consider the nature of the client-service interactions imposed by the contract to design the APIs as fine-grained or coarse-grained.


Return a resource representation for Creation and Updates

A PUT, POST or PATCH call may make modifications to fields of the underlying resource that weren't part of the provided parameters (for example: created_at or updated_at timestamps). To prevent an API consumer from having to hit the API again for an updated representation, have the API return the updated (or created) representation as part of the response.


Define a consumable error payload

Just like an HTML error page shows a useful error message to a visitor, an API should provide a useful error message in a known consumable format. The representation of an error should be no different than the representation of any resource, just with its own set of fields.


Consider Connectedness

One of the principles of REST is connectedness—via hypermedia links. While services are still useful without them, APIs become more self-descriptive when links are returned in the response. At the very least, a 'self' reference informs clients how the data was or can be retrieved. Additionally, utilise the Location header to contain a link on resource creation via POST. For collections returned in a response that support pagination, 'first', 'last', 'next' and 'prev' links at a minimum are very helpful.


Enhance Concurrency

Server-side concurrency is needed to effectively reduce network chattiness. Without concurrent execution on the server, a single "heavy" client request might not be much better than many "light" requests because each network request from a device naturally executes in parallel with other network requests. If the server-side execution of a collapsed "heavy" request does not achieve a similar level of parallel execution it may be slower than the multiple "light" requests even accounting for saved network latency


Use Common URI Conventions

With respect to URIs, RESTful APIs should:

  • Use transparent (readable) URIs unless specific requirements preclude

  • Use dashes (aka hyphens) in lieu of underscores (when easily supported by your framework)

  • Use dashes (aka hyphens) in lieu of camel case. (This is proposed only for API URLs, and only if supported by your framework.)

  • Support nested resources when doing so is logical and only two levels deep

  • The use of plural resource names is preferred, but not required. For example, it is proposed to use 'colleges' versus 'college' for URLs used to refer to both collections and specific elements within a collection. Using singular naming is not incorrect, but using plural naming is also common and may arguably read better.

  • Representations for a collection and a single instance of a resource are to be considered the same resource from an addressing perspective. That is, a list of colleges may be referenced as /colleges, a specific college instance may be referenced using a URI such as '/colleges/college-43'.


API Documentation

An API is only as good as its documentation. The docs should be easy to find and publically accessible. The docs should show examples of complete request/response cycles. Swagger seems to have become the default standard for defining, implementing, discovering and testing REST services.


Use Standard HTTP methods

APIs should at a minimum expose a standard REST interface using the four HTTP methods (aka verbs) shown below:

HTTP Method

Description

GET

Read a resource or list of resources

POST

Create a new resource

PUT

Update an existing resource or create one if the key is pre-defined

DELETE

Remove a resource

Use HTTP status codes

RESTful APIs should be designed to use standard HTTP status codes. The following status codes are recommended:

HTTP Status Code

Description

200

The request was successful.

201

A resource was successfully created.

202

Request has been received. This is only used for asynchronous processing.

304

The GET request was conditional and contained an 'If-None-Match' header that was used to determine the current representation has not changed

400

The request cannot be understood. This should be used if there are syntax errors and validation errors, (422 is also acceptable for validation errors.)

401

Authentication has failed, or the authenticated client is not authorised.

404

The requested resource could not be found.

405

The method is not supported by the resource.

406

Not Acceptable. Return this code when the Accept header identifies an unsupported format.

409

There is a conflict. Return this if the request reflects stale data (that violates an optimistic lock).

412

A precondition failed. Used for conditional requests (e.g., when an 'If-Match' header does not match a resource's Etag value).

415

Unsupported Media Type. Return when a client requests content in an unsupported format.

417

Expectation Failed. Return this if appropriate when supporting 'look-before-you-leap' requests.

422

Unprocessable entity.

429

The rate limit is exceeded.

500

An undisclosed server error occurred.

Use API Versioning

It is important to version APIs in order to provide clients with stability. Versioning helps you iterate faster and prevents invalid requests from hitting updated endpoints. There are several common approaches used across the industry today for versioning RESTful APIs, the most common being to specify a version:

  • within the URL: /loans/home-loans/accounts/v1/{1234234}/ or /loans/home-loans/accounts/v2/{1234234}/transactions/v2/

  • using a query parameter: /loans/home-loans/accounts/{1234234}?version=1

  • using a custom media type identified in the Accept and Content-Type headers: Accept: application/loans.homeloans.account+json;v=2

RESTful APIs should use custom media types (previously known as 'MIME types') to allow client applications the ability to interact with a stable, versioned API when desired. With this approach resource representations transferred to the client are versioned. The advantage of this approach is that each resource is versioned independently and incremented individually.


Embedding the API version into the URI disrupts the concept of uniform interface (REST guideline) by having a resource URI that would change over time.


Support Pagination

When returning collections, it may be necessary to support paging. There is no single standard for paging, however 'page' and 'per-page' are recommended, the specific query parameter names may differ based upon your framework.


Understand Common REST Design Patterns

Asynchronous Processing with REST Asynchronous processing may be supported by having an endpoint perform work asynchronously, and immediately return a '202' status code with a link that the caller may subsequently use to check the status of the asynchronous process.

  • Business Transactions with REST SOAP allows for externalisation of business transactions using WS-BusinessActivity. Business (aka logical) transactions may be modelled explicitly as a resource, so that a business transaction can be started using a POST, status updated using PUT, and committed using PUT and or DELETE.

  • Reliable Messaging with REST While REST does not have built-in 'reliable messaging' support, it uses synchronous communication over the HTTP protocol and can thus recover more safely from potentially lost messages.


Governance

Governance is a broad area that may encompass service registries, service repositories, schema catalogues, server configurations, service management (consumption, usage patterns, etc.), and even development processes.

Service repositories are used to centrally store information about the services that are present in your organisation's service inventory whereas service registries are often used at runtime to help with problems like endpoint resolution.

At a minimum, a lightweight process and an organisation-wide schema reuse library, data dictionary, or repository is needed to promote commonality across an organisation creating APIs. One can also build their own simple service repository or use tools such as IgniteXML.

Governance should ensure consistent exposure of resources with respect to representations and semantics.


API Management

At the highest level, an API management solution needs to include a –

  • Developer Portal for developers to discover APIs, understand usage and sign up for access

  • API Gateway that secures and mediates the traffic between your APIs and its consumers

  • API Lifecycle Management to manage the process of designing, developing, deploying, versioning and retiring APIs


To Conclude

Well-designed APIs clearly define their purpose, making it easier for developers to understand and utilize their capabilities. By following consistent naming conventions, providing comprehensive documentation, and adopting industry standards, businesses can ensure that their APIs are intuitive and easy to integrate.

Comentarios


bottom of page