Photo by Helloquence on Unsplash (Edited)

The Contract

The importance in getting the API correct and the initial design of the API.

The Contract

The fundamental assumption I am making with this application is that it will be consumed over the network. There are two different was we can express the internal state of this application over the network:

  1. As an interface through which clients can make specific remote procedure calls (RPCs) and receive structured information but no user interface

To render or not to render

In small teams and within a limited use case the first approach in which the user interface (via HTML documented) makes some sense. It is:

  • Quickly shippable
  • Easy to reason about

On a long enough timeline, all things become an API

Just about all software is subject to change over time. However, not all software changes in a way that makes future changes easy to accomplish. It is perhaps easiest to provide a concrete example.

Team coordination is expensive

In a large enough software company software is going to be consumed by people who work in different teams, or people who work outside the organisation.

  • Scheduling difficulties
  • The need to concentrate on software development
  • The need to establish a common language about the software stack

Contracts up front

As with any kind of agreement it is generally expensive renegotiating a given agreement when requirements change or a requirement that was clear to one party was not clear to another.

RPCs are language independent — hopefully

The value in a language interoperable RPC is users who have a limited knowledge of the application itself but understand the nature and format of the RPC can consume the services exposed by the application. For example, a developer who likes working in Python can query a service written in PHP so long as they follow the RPC conventions; not even knowing that this service is PHP.

Choosing the RPC tooling

There are several kinds of RPC tooling, but the ones I use the most and have the most experience with are:

  • OpenAPI (formerly Swagger)

The spec itself

Versioning

Because of the cost and complexity involved in change an API I will tend to push an API through three stages, modelled after the versions exposed by the Kubernetes. There are three phases:

  1. Beta — This API appears to be a good representation of the problem but because there is only limited adoption of the alpha APIs there might be issues that have been unforeseen.
  2. Stable — This API is good. We will try very hard never to break it.
v1alpha1
  1. alpha - The current lifecycle stage of this API
  2. 1 - How many times this API has changed within its current lifecycleOnce an API is in v1 it should essentially never be broken. This can never be guaranteed indefinitely, but a guarantee of 12 or 24 months deprecation period should be ample.

Routing

If implemented over HTTP, each version is at a separate endpoint. For example,

  • /v1alpha1/${METHOD_B}
  • /v1beta1/${METHOD_A}
  • /v1/${METHOD_A}

Entities

More generally I will tend to first define the minimal properties of the entity and create a set of sane requests and responses — that is, full out a “fully functional” API before implementing too much logic associated with the entities and the responses.

Hypermedia / Links

Within an API design I will tend to make use of hypermedia links rather than attempting to determine how many of a given object should be embedded in the response.

Error object

Errors are an interesting class of API return.

  • TCP RST? Something badly went wrong there. You know that you don’t know.
  • Empty response? Something went wrong at the HTTP layer. You know that you don’t know, but the app probably did not function correctly
  • HTTP response? Great! You have an abundance of information; status codes, headers and so fourth.
  • The HTTP message body? Hmm. Value can vary.
  1. Not automatically repairable. Needs to be surfaced to a human to address.
{
"uri": "e.wrkpi.pe/9bccc946-d4b3-11e9-a6d2-0ffe87baa1be",
"description": "Unexpected FooCondition"
}

Authentication

As of the time of writing there is no authentication.

In Conclusion

The communication boundary of a service influences the conceptual model of that service, and whether intentional or not how users consume that service becomes its API.

Further Reading

I have additionally written on this topic at: