Files
agiledancers/adr/refined/ADR2_http-api-contracts-and-tooling.md
Wanja Krah 0f1c5dcd92
All checks were successful
Build, test and publish / verify (push) Successful in 7m44s
skill development and ADR sessions
2026-11-06 13:26:25 +01:00

177 lines
10 KiB
Markdown

**ID:** ADR2 \
**Title:** HTTP API contracts and tooling \
**Supersedes:** - \
**Status:** REFINED \
**Expiration Date:** Six months after approval; record the calendar date upon manual approval.
## Context
Agile Dancers currently uses REST without an explicit architectural decision.
The landscape needs agreed defaults for communication across system boundaries,
contract documentation, client generation, compatibility, and error handling.
Interactions include frontend access, requests between business systems,
delegation of long-running calculations to workers, change notifications, and
external consumers. Most clients and servers are developed by the same maintainer.
Consumers must nevertheless be able to upgrade independently. The independently
deployable systems proposed in ADR1 are relevant context; ADR1 remains REFINED
and is not approved through this decision.
The current frontend uses Angular, but future clients may use other frameworks
or languages. Contracts and tooling should support that flexibility.
For now, interactions use a defined alternative path when another system is
offline. Durable queued delivery is not a current requirement. More specialized
communication mechanisms may become appropriate for particular interactions.
## Decisions
### Scope and communication style
Use HTTP APIs with JSON payloads as the default across system boundaries.
Use resource-oriented endpoints where natural and action-oriented endpoints
where they express business intent more clearly. Do not force business actions
into CRUD operations. For example:
```text
GET /api/v1/schedules/{id}
POST /api/v1/schedules/{id}/calculate
```
Action endpoints still follow HTTP method and status semantics. For long-running
work, use an explicit job or operation resource with a status endpoint when the
caller needs to track progress. A notification can initially use a direct HTTP
request with documented failure behavior; this does not promise durable delivery.
These are landscape defaults. Document justified exceptions alongside the
relevant interface, including the reason and the alternative contract and failure
behavior. This ADR does not mandate GraphQL, RPC, or messaging infrastructure.
### Contracts and documentation
Describe HTTP APIs using OpenAPI. Normally generate the description from server
code, adding explicit descriptions and annotations where needed. Review the
resulting contract as a public interface; generation alone does not ensure
completeness or backward compatibility.
Use self-hosted Scalar API Reference as the default interactive documentation UI.
Keep the OpenAPI document independently available so consumers and tooling do not
depend on the UI. Publish a contract artifact for each supported major version.
Choose an OpenAPI specification version supported by the server tooling, Scalar,
and the selected client generators. Do not automatically adopt the latest version
without checking that compatibility.
### Client generation
Generate client transport code and contract types from OpenAPI by default, using
OpenAPI Generator. Select the generator appropriate to the consuming technology;
use `typescript-angular` for Angular clients. This choice does not require future
frontends to use Angular.
Pin generator versions and configuration for reproducible generation. Generate
against a selected contract artifact rather than requiring a running server during
the client build. Keep generated code separate from handwritten application logic
and do not manually edit generated files. Generated static types do not by
themselves provide runtime response validation.
### Versioning and compatibility
Put the major contract version in the URL, such as `/api/v1/schedules`.
Keep backward-compatible changes within that major version. Introduce a new
major version for breaking changes. Software release and generated client package
versions may advance independently of the major contract version.
Allow consumers to upgrade independently. Normally support one contract version;
during transitions, aim to support two. This is a guideline rather than a hard
cap: additional versions may coexist when justified. Document supported versions,
deprecation, and the transition plan, coordinating retirement with affected
consumers. Check compatibility before releasing contract changes.
### Errors and offline behavior
Standardize API error bodies on RFC 9457 Problem Details using
`application/problem+json` and appropriate HTTP status codes. Use stable problem
`type` identifiers for programmatic handling and readable explanations for humans.
Clients must not depend on parsing human-readable messages. Document expected
errors in OpenAPI, including validation details where applicable. Do not expose
internal exception details or sensitive information in error responses.
Define timeouts and the offline alternative path for each interaction. A network
failure may produce no HTTP response, so consumers must handle that separately
from a Problem Details response. Avoid automatic retries of actions unless
repeating them is safe. Do not assume durable delivery or eventual replay.
### Adoption and review
Adopt incrementally for new interfaces and interfaces being substantially changed.
Migrate existing interfaces through planned work while preserving compatibility
for existing consumers. No immediate landscape-wide rewrite is required.
Review six months after approval, or earlier if integration needs expose
limitations. The review date triggers reevaluation rather than automatic expiry.
## Options considered
### Communication approach
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| Resource-oriented HTTP/JSON with action endpoints | Readable resources and business actions; supports different client technologies; retains HTTP semantics. | Requires consistent endpoint conventions and explicit handling of long-running work and failures. | Chosen as the default. |
| GraphQL | Flexible data selection; typed schema; supports different consumer views of related data. | Adds query authorization and performance concerns; requires additional conventions for work delegation and notifications. | Not chosen: current needs and common client/server ownership do not justify the added complexity. |
| RPC, including JSON-RPC and gRPC | Explicit operation contracts; JSON-RPC is lightweight; gRPC supports strongly typed generated clients. | Operation-oriented contracts require careful evolution; gRPC adds browser integration requirements. | Not chosen as the default: resource-oriented HTTP with optional actions better matches the desired interface flexibility. RPC remains a possible justified exception. |
### Contract description and authoring
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| OpenAPI, normally generated from server code | Language-independent HTTP contracts; supports documentation and client generation; avoids separately maintaining a design language. | Needs annotations, review, and compatibility checks; generated output can be incomplete. | Chosen. |
| TypeSpec generating OpenAPI | Dedicated contract authoring language; can generate descriptions and other artifacts. | Adds a language and compiler to maintain. | Not chosen: no current benefit sufficient to justify the additional tooling. |
| RAML | API description language with reusable modeling constructs. | Its specification repository is archived, creating a maintenance concern for a new standard. | Not chosen. |
### Interactive documentation
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| Scalar API Reference | Readable interactive documentation; integrated request testing; self-hosting and configuration options. | Requires integration and maintenance alongside the server framework. | Chosen: readability and testability are the primary purposes of the UI. |
| Swagger UI | Interactive requests and authentication support; direct integration with Quarkus OpenAPI tooling. | Its expandable operation layout is less aligned with the preferred reading experience. | Not chosen as the landscape default. |
### Client generation
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| OpenAPI Generator | Supports Angular and other client technologies in one tool family; configurable generation. | Generator-specific options and upgrades need management. | Chosen to support future technology changes. |
| ng-openapi-gen | Angular-focused generation; npm-based tooling. | Other client technologies require another generator. | Not chosen as the landscape default. |
| Handwritten clients | Direct control over client code and application integration. | Duplicates contract types and request details; increases drift risk. | Not chosen as the default. |
## Consequences
- Apply the defaults to new and substantially changed interfaces. Plan migration
of existing interfaces incrementally, preserving consumer compatibility.
- Generate and publish versioned OpenAPI artifacts. Add Scalar to provide
interactive documentation and request testing for supported contracts.
- Establish pinned OpenAPI Generator configurations for client technologies,
initially Angular. Keep generated code separate from application logic.
- Add contract validation and compatibility checks to release workflows. Verify
generated clients against the actual contract before adopting generator upgrades.
- Introduce URL major versions and coordinate deprecation with consumers. Normally
maintain one version and temporarily two, documenting justified deviations.
- Align API error responses with Problem Details and document expected failures.
Define timeout and offline behavior per interaction, including safe retry rules.
- Record justified exceptions alongside their interfaces rather than imposing an
unsuitable communication mechanism on every interaction.
- Record the calendar review date upon manual approval. REFINED captures the
agreed proposal; approval remains a separate manual step.
### References
- [OpenAPI specification](https://spec.openapis.org/oas/)
- [Scalar API Reference configuration](https://scalar.com/products/api-references/configuration)
- [OpenAPI Generator: TypeScript Angular](https://openapi-generator.tech/docs/generators/typescript-angular/)
- [RFC 9457: Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457.html)
- [Swagger UI configuration](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)
- [TypeSpec overview](https://learn.microsoft.com/en-us/azure/developer/typespec/overview/)
- [RAML specification repository](https://github.com/raml-org/raml-spec)
- [JSON-RPC specification](https://www.jsonrpc.org/specification)
- [ng-openapi-gen](https://github.com/cyclosproject/ng-openapi-gen)