Design for REST. If the interaction appears RESTful then develop a REST API, for example, one to many. In some cases, however, a gRPC or GraphQL API may be appropriate and are supported by these guidelines. REST APIs are widely understood, easier to govern and suitable for most interoperability use cases. It is also important to note here that if there is an appropriate supported standard such as Fast Healthcare Interoperability Resource (FHIR) then the resources defined in that standard should be used rather than a set of agency-defined resources.

The information supplied via an API may still be dependent on overnight batch processes for updates. It is worth making the information’s timeliness and update period clear to potential consumers of the API.

APIs should not be used to handle large batch transfers because if one single data write fails then the whole batch fails. APIs work better for multiple individual update transactions.

1.2.6. Design-driven development — Required

When building APIs, a design-driven approach must be taken. This includes:

Interface specification first

The best way to design an API is in collaboration with potential consumers of that API. Creating the interface specification first makes it easier for application developers to see what the API is going to offer and how it could be used.

Consumers’ early feedback will ensure that the API design is heading in the right direction and will be usable and appropriate to their needs. Using a simple modelling language to define the interface specification makes it easy to view and edit API definitions.

Iterative approach

It has been acknowledged that big bang releases rarely deliver business or customer benefit. An iterative approach, with ongoing releases offering gradual improvement or evolving capability, gives a finer tuned delivery, better sense of momentum, illustrates progress and enables third parties to coordinate efforts with API developments.

An iterative approach incorporates continuous improvement, which recognises the need to support continuing evolvement of the API beyond the first delivery. The API is a product whose capabilities should undergo continuing improvements based on consumer feedback, performance analytics and emerging needs.

Continuous integration / testing

Automation provides a quick turnaround for informing API developers about breaking changes being submitted by developers who are all working on the same code base or product, for example, an API. The idea is that all developers submit code changes as often as possible (for example, into a version control system) allowing code to go through an automated, integrated build process that ensures that nothing has broken the build. This build process could happen many times a day. Any errors are quickly identified and alerted to the team who can rectify them in a timely fashion.

Tests can be written against the interface specification quite early on in the development process by developing just enough API code to enable the test to be run (stubs). The tests can then be incorporated into the automated build process, giving early warning of regression test failures. API code should not be able to progress through Software Development Life Cycle (SDLC) environments until successful test execution.

1.2.7. Granularity

There is a question as to how fine-grained an API resource should be. APIs should be designed at the lowest practical level of granularity because this makes each service simpler and allows them to be combined in ways that suit the application developer. The key principle is to design services that can be re-used and combined in different ways, and not tie the application developer to a specific way of working or sequence of API consumption just because that is how it is configured or built in the backend.

If an API offers very fine-grained resources, then consuming applications end up having to make many more calls to the API in order to collect all the information they need, resulting in chattier communications. On the other hand, if the API is based on very coarse-grained resources (returning everything about the resource) the response payloads could end up being enormous, may not support all API application developers’ needs, and the API could become cumbersome to use and maintain.

There may also be a need for varying granularity within one API, depending on the purpose and use of that API. For example, if a blogging API was being created, it may make sense to offer a coarse-grained resource for posting a new blog entry as a bundle of content including pictures, sound, keywords as well as the textual blog entry. But when offering the ability to like or comment on a blog entry it would make sense, for clarity and ease of use, to offer these as separate sub-resources, one for indicating a ‘like’ and one for submitting a comment.

It is important to aim for a granularity that will prevent business logic from leaking into the API, for example, requiring API calls to be made in a certain sequence to meet with internal business processes. With the blogging example, consider the impact of a fine-grained API being offered for posting blog entries, with separate calls for adding images, sounds and metadata. If metadata is mandatory, then the API application developer needs to ensure that every blog post call is followed by a metadata call. This puts the onus on the application developer to get the sequence of calls correct and could lead to inconsistent data if they do not adhere to the rules. It also leads to close coupling between the consuming application and the API, and if the business logic changes in the future there is a downstream impact on all application developers, requiring them to modify their applications.

General guidelines are:

Do not aim for the finest granularity — an API should be built around each discrete and updateable resource.

There does not need to be a 1-to-1 mapping between a manual service and a corresponding API. APIs should support the process but not try to encapsulate the process.

A rough guide is to have one API operation for each entity life cycle state transition.

Resources can be identified by reviewing a business process and identifying the key entities that underpin the process. Any entities that the organisation manages or maintains throughout its full life cycle will be potential API resources. There is typically one API operation for each entity life cycle state transition.

There should be only 1 API function for 1 business outcome, for example, change an address.

Consider using query parameters in URLs for different granularity of resources. For example, ‘/passengers.json’ could return a list of names, while ‘/passengers.json?detail=full’ could return detailed information about each passenger in a list.

1.2.8. Interface specification

An API represents a contract between the provider and the consumer for access to provider resources. Because API consumption is a programmatic exercise, it is important to have a clear definition of what the API offers and how those API resources are to be accessed. This definition is the interface specification.

The interface specification should be designed in advance of developing the API, as the act of working out the specification often helps think through all the issues that could impact the design of the underlying resource-handling code. It also helps consuming application developers to review the capabilities being offered to see if the capabilities meet their needs before they start developing to the specification. When outsourcing API development, the interface specification can be written in abstract as a means of defining the API the vendor should build. The specification can be handled as a separate entity, is version controllable, and it should be possible to use it as the main API documentation or reference.