# `endpoints/ui-proxy` — `/graphql/ui` proxy ## Purpose `endpoints/ui-proxy` mounts the `/graphql/ui` endpoint. The Apollo engine never embeds Apollo's landing page — UI is opt-in via a separate package (GraphiQL, Altair, …), identical to Yoga's stance. When no UI plugin is wired the endpoint returns `404` with a short text body explaining the policy; when a plugin is wired the endpoint forwards its `render()` output verbatim. This module is deliberately framework-agnostic: it accepts a `@suaveplan/api-router` `Router` and a UI plugin descriptor with a `render()` method. The host wires whichever GraphiQL / Altair package it prefers without the engine becoming aware of the choice. ## Features - 404 by default — no Apollo landing page leakage. - Custom mime type — UI plugins that ship binary (e.g. WASM) bodies can override the default `text/html`. - Driven by `ApolloGraphqlOptions.uiEndpoint` — operator can rename the path. - Returns a teardown handle reserved for future hot reload. ## Usage: Basic ```ts import { Router } from "@suaveplan/api-router"; import { mountGraphqlUiProxy } from "@suaveplan/api-graphql-apollo/endpoints"; import { parseApolloGraphqlOptions } from "@suaveplan/api-graphql-apollo/options"; const router = new Router(); mountGraphqlUiProxy({ router, options: parseApolloGraphqlOptions(), ui: null, }); // GET /graphql/ui → 404 ``` ## Usage: Advanced Wire a GraphiQL-style UI plugin so the same router serves the playground at `/graphql/ui`: ```ts mountGraphqlUiProxy({ router, options, ui: { render: () => `
`, }, }); ``` ## API Reference - `GraphqlUiPlugin` — `{ render(): string; contentType?: string }`. - `UiProxyResponse` — `{ status: 200 | 404; body: string; contentType: string }`. - `mountGraphqlUiProxy(args): () → void`. ## Implementation Notes The UI plugin contract is intentionally minimal — `render()` returns a string and the proxy serves it. Future evolution (CSP nonces, per-tenant configuration) lives in the UI plugin itself, not in this module. The 404 response body is `text/plain` so curl users see a human-readable explanation rather than an empty page.