first commit
This commit is contained in:
85
docs/api-stack/api/api-plugin-tenant/src/routes/routes.md
Normal file
85
docs/api-stack/api/api-plugin-tenant/src/routes/routes.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# `routes`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Builds the five OpenAPI route entries `createTenantPlugin` mounts when a
|
||||
`TenantStore` is configured: `GET /`, `POST /`, `GET /:id`, `PATCH /:id`,
|
||||
and `DELETE /:id`, each paired with a Hono handler that delegates to
|
||||
the `TenantService`. Every body, query, and response shape flows
|
||||
through the Zod schemas from `schemas/routes.ts` so the unified
|
||||
OpenAPI 3.1 document the host serves stays in lock-step with the
|
||||
runtime behaviour.
|
||||
|
||||
## Features
|
||||
|
||||
- Five-route CRUD surface returned as `PluginRouteEntry[]` ready for
|
||||
`definePluginRoutes`.
|
||||
- Per-handler Zod validation — bodies, query parameters, and path
|
||||
params are validated explicitly with `safeParse` so the error
|
||||
shape is consistent across all five handlers.
|
||||
- Domain → wire projection via `toResponse` so `Date` fields serialise
|
||||
as ISO strings and optional `plan` / `metadata` keys are omitted
|
||||
rather than serialised as `null`.
|
||||
- `TenantPluginError` instances are translated to JSON `{ success:
|
||||
false, error: { code, message } }` with the carried `statusCode` so
|
||||
callers see 404 / 409 / 500 as appropriate.
|
||||
- Soft-delete success response is `{ success: true }`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { buildTenantRoutes, createTenantService, MemoryTenantStore } from "@suaveplan/api-plugin-tenant";
|
||||
import { headerResolver } from "@suaveplan/api-tenant";
|
||||
|
||||
const store = new MemoryTenantStore();
|
||||
const resolver = headerResolver("x-tenant-id", (id) => store.getById(id));
|
||||
const service = createTenantService({ resolver, store });
|
||||
const entries = buildTenantRoutes(service);
|
||||
console.log(entries.length); // 5
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { buildTenantRoutes, createTenantService, MemoryTenantStore } from "@suaveplan/api-plugin-tenant";
|
||||
import { headerResolver } from "@suaveplan/api-tenant";
|
||||
import { definePluginRoutes, createOpenAPIRegistry } from "@suaveplan/api-openapi";
|
||||
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||
|
||||
const store = new MemoryTenantStore();
|
||||
const resolver = headerResolver("x-tenant-id", (id) => store.getById(id));
|
||||
const service = createTenantService({ resolver, store });
|
||||
const app = new OpenAPIHono();
|
||||
const registry = createOpenAPIRegistry({ info: { title: "demo", version: "0.0.1" } });
|
||||
const entries = buildTenantRoutes(service);
|
||||
|
||||
// Caller is responsible for prefixing the paths and applying any RBAC middleware.
|
||||
const prefixed = entries.map((e) => ({
|
||||
...e,
|
||||
route: { ...e.route, path: `/tenants${e.route.path === "/" ? "" : e.route.path}` },
|
||||
}));
|
||||
definePluginRoutes(prefixed, { app, registry, pluginName: "tenant" });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `function buildTenantRoutes(service: TenantService):
|
||||
PluginRouteEntry[]` — returns five entries. Path templates use
|
||||
`/{id}` for the resource routes (OpenAPI style), which Hono accepts
|
||||
via the `app.openapi(route, handler)` integration in
|
||||
`definePluginRoutes`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The handlers validate inputs even though `definePluginRoutes` already
|
||||
wires `c.req.valid(...)` because we want the same handlers to be
|
||||
runnable on a Hono-only mount (no OpenAPI registry) without losing
|
||||
boundary validation. Errors are JSON-formatted with explicit status
|
||||
codes so consumers using a thin error handler do not need to know
|
||||
plugin-internal error shapes. The list response shape (`{ items,
|
||||
total }`) is deliberately minimal; consumers needing cursor-based
|
||||
pagination wire their own variant or subclass the schema.
|
||||
Reference in New Issue
Block a user