Files
skills/docs/api-stack/api/api-plugin-tenant/src/routes/routes.md
2026-05-29 08:20:56 +01:00

3.4 KiB

routes

(no submodules)

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

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

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.