All checks were successful
Build, test and publish / verify (push) Successful in 7m44s
177 lines
10 KiB
Markdown
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)
|