All Individual API Endpoints will be named and versioned according to the following rules:
All endpoints URIs will be under the /api path in the backend.
The general structure of any endpoint will be /api/<version>/<path>
<version> defines a version of the endpoint supplied by a <path> and is NOT aligned with any other versions.
<version>MUST either be draft or matching the regular expression ^v(?!0)\d{1,}$1
<path> Can be any path of at least one element as required for the endpoint.
ALL new endpoints start as draft they are promoted to a versioned endpoint by a deliberate decision.
New endpoints MUST NOT be versioned other than draft in their initial PR.
New endpoints can only be versioned after the behavior and form of the endpoint has been validated, in a subsequent PR.
ALL draft endpoints are subject to change and can be safely modified in any way.
draft Versioned endpoints can be used by frontend code.
However, if the API changes or disappears, the front end should fail gracefully.
The numbered version of an endpoint will always start at v1 and increments sequentially.
API versions are ONLY incremented if their behavior changes in a way that can reasonably be considered a breaking change
with respect to the currently published OpenAPI specification for that Endpoint.
The API endpoint versions are not aligned to any semantic versioning of the backend.
draft endpoints should not be tested in CI, in such a way as they break the CI pipeline if they change.
ALL versioned endpoints SHOULD have CI tests which ensure the API endpoint itself has not changed in a breaking way.
Code generation can generate code for draft endpoints, provided doing so does not result in breaking CI.
Any Integration tests written against draft endpoints should not fail.
They may produce warnings if they do not match expected outputs.
Re-versioning an endpoint is NOT required if the change to it is backward compatible with the existing endpoint.
A non-exhaustive list of possible cases for this are:
A new OPTIONAL query parameter is added to an endpoint.
A response field is added, and the OpenAPI document defined that "additionalProperties": true
in the schema definition where the additional field is to be added.
A previously undocumented behavior is documented.
In this case, the behavior must already exist, it is not a breaking change to clarify documentation.
ALL non-breaking changes proposed in a PR to existing API's,
or migrating an API from draft to a versioned API MUST be signed off by
at least 1 Architect on the Team; and
the Engineering manager; and preferably
A senior member of the team with primary responsibility for the frontend.
When a new version of an endpoint is released, the existing endpoint MUST be marked as deprecated
in the OpenAPI specification for the endpoint.
This MUST occur in the same PR as the PR that moves the endpoint from draft to a versioned API.
PRs which version a draft endpoint SHOULD ONLY include the following.
There can be no other changes to the logic in an API versioning PR.
Updating any draft integration tests to match the new version of the endpoint, and ensure they will Fail CI if they fail.
There is no requirement that draft endpoints must enter production.
Endpoints can go from draft to a versioned endpoint during the development of a single release.
Conversely, there is no problem with draft endpoints entering production if they are not stable at the time of a release.
draft endpoints have the same security requirements as versioned endpoints.
The only difference is the query parameters, path or responses are not stable and can change.
The purpose of these rules is to allow us to iterate quickly and implement new API endpoints.
And remove unnecessary risks of breaking the front end, or CI, while adding new endpoints.
Currently, the API is mostly unstable.
We also do not have any external consumers of the API to consider.
However, once we enter production with the API we will need a strategy for deprecating and removing obsolete API endpoints.
That will be the subject of a further ADR related specifically to that topic.
^ asserts the position at the start of the string.
v matches the character v.
(?!0) is a negative look-ahead assertion that checks if the digit after 'v' is not equal to 0.
\d{1,} matches one or more digits (1 to unlimited) which ensures that there are no leading zeros in the numeric part of the string.
$ asserts the position at the end of the string.
For example, v123 would be a valid string, but v0 or v00789 would not match this pattern because they have leading zeros in the numeric part of the string. ↩