Make product API versions independently installable
This commit is contained in:
1 parent
ce6583f454
commit
d04c8b12ab
69 files changed
+755
-404
No files matched your search
@@ -0,0 +1,91 @@
|
||||
# Installing product HTTP API versions
|
||||
|
||||
The product executable selects supported implementations in
|
||||
`backend/product/app/profile/runtime.go`. Each entry maps a version name to an
|
||||
`api.Installer`; v1 composes the existing authentication and second-factor
|
||||
contracts. Adding an implementation requires a package and a registry entry,
|
||||
without changing runtime installation code.
|
||||
|
||||
Select installations in the product YAML:
|
||||
|
||||
```yaml
|
||||
api:
|
||||
versions:
|
||||
- version: v1
|
||||
path: /api/v1
|
||||
# Existing middleware, storage and notification configuration follows.
|
||||
```
|
||||
|
||||
Only v1 ships today. Once a v2 implementation is registered, a second entry with
|
||||
`version: v2` and `path: /api/v2` serves both versions in the same process. Each
|
||||
version can be selected once. Unknown/unavailable versions, duplicate versions,
|
||||
overlapping mounts, noncanonical paths and mounts occupying operational endpoints
|
||||
fail startup. Paths must be absolute, non-root, without trailing slashes, URL
|
||||
escapes, queries, fragments or router pattern syntax. Mounts use ASCII letters,
|
||||
digits, slashes, hyphens, underscores, periods and tildes.
|
||||
|
||||
Omitting `versions` retains compatibility: v1 mounts at the path in the environment
|
||||
variable named by `api.middleware.api_endpoint_env` (normally
|
||||
`SXCHNGE_API_ENDPOINT=/api/v1`). An explicit `versions: []` installs no application
|
||||
routes; process infrastructure and operational endpoints remain available.
|
||||
|
||||
The endpoint environment variable continues to locate the process health and
|
||||
metrics compatibility endpoints, including when explicit application mounts are
|
||||
used. With `/api/v1`, these are `/api/v1/health`, `/api/v1/metrics` and `/metrics`.
|
||||
Keep this value unchanged when adding a version. Health is outside application
|
||||
middleware; the existing HTTP collector excludes operational traffic. These
|
||||
operational endpoints are reserved and are never version-owned contracts.
|
||||
|
||||
## Ownership and lifecycle
|
||||
|
||||
Runtime bootstrap opens shared stores once and injects those stores into the
|
||||
customer service, auth flow and second-factor service. Notification connections
|
||||
are opened once. Every installer receives the same typed dependencies and its
|
||||
own router, validated mount, URL provider and logger. Installers register routes
|
||||
relative to their mount and do not open or close process resources.
|
||||
|
||||
Auth v1 handlers, request DTOs and response mappers live under
|
||||
`backend/product/auth/http/v1`; factor transport lives under
|
||||
`backend/product/twofactor/http/v1`. Models, services and storage remain in their
|
||||
owning features. A future version owns its wire contract and reuses domain
|
||||
services, so changing its DTOs does not silently change v1. The generic runtime
|
||||
and HTTP middleware do not import concrete API versions.
|
||||
|
||||
All version routers are built before any application router is attached. An
|
||||
installer error aborts startup, preserves the cause and closes shared resources.
|
||||
Bootstrap must either return a cleanup callback for resources it opened or close
|
||||
them itself before returning an error; it must not do both. The built-in bootstrap
|
||||
cleans its partial initialization internally. Runtime invokes an acquired cleanup
|
||||
callback once, including on installation failure or repeated/concurrent shutdown.
|
||||
The server retains ownership of the shared database factory.
|
||||
|
||||
The removed generic service registry and untyped runtime component lookup have no
|
||||
product consumers. The typed dependencies and installer registry replace them.
|
||||
This changes internal Go composition APIs; public v1 JSON and HTTP paths remain
|
||||
compatible. No database migration is required.
|
||||
|
||||
## Cookies and links
|
||||
|
||||
Runtime binds browser cookie scope to the installed mount using request context.
|
||||
Set and clear operations use the same `<mount>/accounts` path. The existing v1
|
||||
path remains `/api/v1/accounts`; `/api/v2` would use `/api/v2/accounts`. Cookie
|
||||
name, host-only policy, Secure, HttpOnly and SameSite settings are unchanged.
|
||||
Changing an existing mount requires clients to authenticate at the new path;
|
||||
cookies at the old path do not migrate automatically. Versions share domain
|
||||
session state, so account-wide revocation continues to apply across versions.
|
||||
|
||||
`API_ENDPOINT` no longer overrides cookies globally. Direct standalone handler
|
||||
calls retain their request-path fallback; installed APIs always use explicit
|
||||
scope. Installers generate API links through `scope.URLs`, which combines the
|
||||
configured origin and that installation's mount. The origin must use HTTP or
|
||||
HTTPS with a hostname and optional port. Configured notification activation URLs
|
||||
remain frontend links and are not rewritten as API links.
|
||||
|
||||
## Validation
|
||||
|
||||
Runtime tests exercise independently behaving versions, shared dependency identity,
|
||||
disabled routes, invalid mounts, scoped links, cookie set/delete behavior, failed
|
||||
installation cleanup and repeated shutdown. The existing Mongo-backed startup
|
||||
test covers the default v1 installation on an empty database. Existing auth and
|
||||
factor tests moved with their transports and retain their contract assertions.
|
||||
Run `make test` and `make lint-backend` from the repository root.
|
||||
Reference in new issue
Block a user