Skip to content
CommonLayer
Documentation menu
On this page

ADR-0007: REST with generated OpenAPI for browsers; gRPC for machine clients

Status: Accepted (plan decision D7). Implemented: the assembled OpenAPI document (docs/api/openapi.json, WP-40) and the gRPC transport (WP-41) exist (amended 2026-11-10).

Context

The brief requires a REST API for browsers. The portal is TypeScript and should not hand-maintain response types. Machine clients (clctl, integrations) benefit from a typed RPC interface.

Decision

  • REST under /api/v1 with Axum; each domain router annotates its handlers with utoipa so that the composition can merge them into one OpenAPI 3.1 document. clctl openapi prints it; the committed copy is docs/api/openapi.json; the portal generates its client types from it (make generate-web).
  • gRPC (Tonic) package commonlayer.v1 for machine clients, calling the same application services. Every RPC maps to an existing service method.

Consequences

  • One authorization path regardless of transport, because both transports call the same services.
  • The router-level test enumerates the OpenAPI document and requires every operation not tagged public to answer 401 without credentials. The public tag is therefore load-bearing (see ADR-0023).
  • Until docs/api/openapi.json exists, the portal uses a hand-written placeholder schema that covers only GET /api/v1/auth/session.
  • gRPC is not implemented yet; it will be documented in its own page under API once available.

Amendment, 2026-11-10

  • The OpenAPI document is assembled by the composition and committed as docs/api/openapi.json; CI fails when it is stale (make check-generated). The portal generates its client types from it; the placeholder schema is gone.
  • gRPC is implemented (WP-41): 12 services and 59 RPCs in proto/commonlayer/v1/, served by the API process, documented in gRPC API. Four RPCs of the plan were dropped because API tokens can never hold the permissions they need or no service read existed; RegistryService.GetPullStats was restored in WP-70b once a pull-statistics read existed. RPCs that only an interactive session may perform have no gRPC equivalent.