chore(api): experimental REST API namespace (/api/experimental)

Merged
SA
2mo ago
+679-4

CORE-2608

Proposed changes

Adds a general-purpose experimental REST API namespace at /api/experimental/.... Endpoints under it are explicitly unstable: they may change shape or be removed in any release without a major-version bump and without a deprecation cycle. The namespace is the contract — hitting /api/experimental/* is opting into instability — so /v1 keeps its implicit semver promise untouched.

This is a mechanism, not a feature: any team can register an experimental endpoint, gather real production usage, then either promote it to /v1 or drop it.

Implements docs/experimental-api-endpoints-plan.md, one commit per step:

  1. feat(api): add experimental API instance — a createApi({ version: 'experimental' }) instance mounted at /api/experimental/<name>, typed APIClass<'/experimental'>.
  2. feat(api): mount experimental router and metrics — mounts the router before the default catch-all and adds a dedicated metrics block so experimental traffic is recorded under version=experimental (the canary used to decide promotion to /v1).
  3. feat(api): add experimental unstable-signal middleware — stamps every experimental response with x-experimental: true and a Warning: 299 ... header (mirrors the deprecation-header pattern); registered on API.experimental only.
  4. feat(rest-typings): add opt-in ExperimentalEndpoints — a separate ExperimentalEndpoints type, re-exported from the package root but deliberately not merged into the Endpoints union, so PathPattern/Method/Path and the stable typed client stay clean. Consumers import it explicitly.
  5. chore(api): add experimental guardrails and docs — a type-level CI guard that fails yarn typecheck if a path is declared in both unions (catches promotion-by-copy-paste), plus the developer guide and design plan.

Only the new typed API (.get()/.post()/.put()/.delete() with AJV validators) is usable on experimental routes — the deprecated .addRoute() path is not extended. Auth, permissions, rate limiting, CORS, and validation all come for free from the shared createApi + middleware chain.

Testing / verification

  • eslint --quiet clean on every touched file.
  • yarn typecheck clean in rest-typings; the overlap guard was verified negatively by temporarily declaring /v1/me in ExperimentalEndpoints — typecheck failed at noOverlapWithStableEndpoints.ts naming the path — then restored clean.
  • Not yet run: the runtime end-to-end checklist (an actual GET /api/experimental/<name> returning the headers), since no experimental endpoint exists yet. Worth confirming when the first one lands.

Further comments

  • The unstable-signal middleware is registered at module load (not in startRestAPI) so it precedes any route added later by endpoint files — Hono runs .use middleware in registration order.
  • Used a second metricsMiddleware block rather than broadening the v1 regex, so the version label stays accurate instead of mislabeling experimental traffic as v1.
  • Generated API docs intentionally skip experimental endpoints (they scan Endpoints, which these are kept out of) — documented as a deliberate decision.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added documentation for experimental REST endpoints, including opt-in usage, lifecycle expectations, warnings, metrics, and promotion guidelines.
    • Added opt-in TypeScript typings for experimental endpoints.
    • Experimental API responses now include warning headers, including for errors and rejected preflight requests.
    • Added path-specific metrics and improved handling for unmatched routes.
  • Tests

    • Added coverage for experimental responses, CORS behavior, 404s, and metrics routing.