Files
suaveplan/openspec/archive/2026-05-26-api-graphql-ui-altair/proposal.md
2026-05-27 23:29:53 +01:00

3.0 KiB

@suaveplan/api-graphql-ui-altair — Altair UI mount at /graphql/ui

Package: @suaveplan/api-graphql-ui-altair Status: PROPOSED Type: new-package Stage: 7 (GraphQL + WebSocket / SSE engines) — see umbrella openspec/changes/api-plugin-foundation/

Why

Per design doc §10.6 Altair is the explicit alternative GraphQL UI alongside GraphiQL: "GET /graphql/ui — GraphiQL (or Altair via api-graphql-ui-altair)". Altair has a richer feature set — environment management, response history, query-saving collections — preferred by teams who do heavy in-browser API development. Operators wire one OR the other; the engine adapters (api-graphql-yoga, api-graphql-apollo) return 404 at /graphql/ui when neither is wired.

This package is the structural sibling of api-graphql-ui-graphiql — same plugin shape, same mount semantics, different bundled UI.

What changes

Net-new package depending on @suaveplan/api-types, @suaveplan/api-router, @suaveplan/api-graphql, @suaveplan/error, @suaveplan/logger, and altair-static (peer; bundled assets).

  • ADDED: createAltairUi(opts) — factory returning a RouterPlugin value mounting GET <uiEndpoint>.
  • ADDED: AltairUiOptions — Zod-validated config: uiEndpoint (default /graphql/ui), graphqlEndpoint (default /graphql), subscriptionEndpoint (default /graphql/ws), theme ("light" | "dark" | "system"), initialQuery, initialHeaders, initialEnvironments (Altair-specific feature).
  • ADDED: Static-asset serving from package's own dist/assets/ (no CDN).
  • ADDED: CSP headers — same posture as the GraphiQL variant.
  • ADDED: GRAPHQL_UI_ALTAIR_* error codes: GRAPHQL_UI_ALTAIR_ASSET_MISSING, GRAPHQL_UI_ALTAIR_ENDPOINT_COLLISION.
  • ADDED: OTel instrument: graphql.ui.requests_total { ui: "altair" } — same metric name as the GraphiQL variant, only the label differs, so dashboards can sum across both UIs.

Out of scope

  • A CDN-fetched Altair variant.
  • The GraphiQL alternative.
  • Co-mounting both UIs on the same path — host config refuses if both are wired against the same uiEndpoint.

Source mapping

Genesis-original. Source of design intent: docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md.

Requirement Design doc section
Altair as alternative at /graphql/ui §10.6
UI as opt-in, separate package §10.6
Bundled assets only §10.6 + foundation security posture

Verification approach

  • src/factory/create-altair-ui.test.ts — factory returns RouterPlugin; HTML response embeds configured endpoints; CSP header.
  • src/factory/create-altair-ui.spec-conformance.test.ts — same conformance shape as the GraphiQL spec — endpoint mount + embedded-config.
  • src/assets/assets.test.ts — no external host references; missing asset raises GRAPHQL_UI_ALTAIR_ASSET_MISSING.
  • tests/integration/altair-end-to-end.test.ts (30000ms) — boots api-graphql-yoga + this UI plugin, Playwright opens /graphql/ui, runs a query, asserts results render.

Migration impact

None — additive only.