Skip to main content

6. v1 API structure

Date: 2021-01-29

Status

Accepted

Context

We have begun implementing a new pattern for API endpoints (dubbed “v1”) to bring a consistent approach, and improve on the “v0” endpoints which are riddled with bespoke code, confusing flow and security concerns.

However, we have never documented this “consistent approach”, instead relying on developers learning and adopting it naturally. As such our v1 API endpoints are liable to fall down the same trap of inconsistency and confusion.

This ADR decision has been reached not through rigorous exploration of best practices, but simply to document the current state so that we can fully convert our endpoints to a consistent style and unlock future improvements.

Decision

API endpoints for v1 controllers must either create a query (Application\Model\Query namespace) if retrieving data, or a command (Application\Model\Command namespace) if writing data, and process it with an associated handler. The controller should not have any dependencies, such as services or repositories.

Data must be sent to the API in JSON format.

Data must be returned from the API in JSON format, using the controller’s serialize method and specifying suitable serialization groups. The data must be returned directly (e.g. {"id": 1, ...}) rather than in a nested object (e.g. {"data": {"id": 1, ...}}).

Any errors and exceptions shall be thrown by the query or command handler, and the v1 controller must pass them to ApiProblem to convert into a standardised error response. There should not be any custom error responses.

Consequences

We acknowledge that once we have adopted this structure we may need to carry out further work to improve the architecture of our APIs. However, adopting a standard structure will make such changes easier, as we will be able to apply them consistently.

We’re also aware that this structure means every command is wrapped in a single database transaction by the https://tactician.thephpleague.com/plugins/doctrine/, which doesn’t allow us to break up large transactions or return partial successes (erroring on some records but saving others). To avoid these issues, we may need to contradict the v1 rules by calling services directly or generating errors manually.

This page was last reviewed on 10 December 2024. It needs to be reviewed again on 10 June 2025 by the page owner #opg-sirius-develop .
This page was set to be reviewed before 10 June 2025 by the page owner #opg-sirius-develop. This might mean the content is out of date.