3.3 KiB
routes/build-routes
(no submodules)
Purpose
The build-routes module constructs the OpenAPIHono instance that the
plugin mounts under routePrefix (/search by default). It declares
the 9 canonical search endpoints — query, suggest, list indexes,
create index, get index, delete index, index document, bulk index, and
remove document — wiring every request through Zod validation via
@hono/zod-openapi, dispatching to the in-memory engine in
service/service.ts, and propagating typed events through the
supplied emitEvent callback. Error responses are normalised to the
canonical { error: string } shape and the HTTP status is driven by
the context.statusCode carried on each SearchError.
Features
- 9 endpoints with OpenAPI 3.1 metadata baked in: every request body / path param / query string is Zod-validated, every response shape declared.
- Typed
SearchRouteEventdiscriminated union so emissions never needas anyand consumers can pattern-match onevent.type. - Typed errors mapped to HTTP via
errorPayload:SearchErrorwithcontext.statusCode === 404maps to 404, every other failure to 400; non-SearchErrorthrowables stringify their message. - Side-effect-free factory —
createSearchRoutesbuilds a fresh router on every call, so concurrent plugin instantiations never share router state. - Pure dispatch layer — the routes carry zero business logic; they exist purely to translate HTTP into service calls and back.
Usage: Basic
import { createSearchRoutes } from "@suaveplan/api-plugin-search";
const router = createSearchRoutes({
indexes,
serviceConfig: {
maxIndexes: 100,
maxDocumentsPerIndex: 100_000,
defaultAnalyzer: "standard",
},
});
app.route("/search", router);
Usage: Advanced
Wire the emitter to the host event bus so domain code can react to search lifecycle:
const router = createSearchRoutes({
indexes,
serviceConfig,
emitEvent: (event) => {
eventBus.emit(event.type, event.payload);
logger.info("search-event", { type: event.type });
},
});
API Reference
createSearchRoutes(deps): OpenAPIHono
Returns the configured router with 9 endpoints registered.
SearchRoutesDeps
{ indexes: Map<string, SearchIndex>; serviceConfig: SearchServiceConfig; emitEvent?: (event: SearchRouteEvent) => void }.
SearchRouteEvent
Discriminated union — search:query:executed /
search:index:updated / search:index:created /
search:index:deleted. Every variant carries type + payload so
emitters can pattern-match without unsafe casts.
Implementation Notes
The error-handling helper errorPayload exists once rather than per
route so the mapping rule (statusCode 404 → 404, anything else →
400) lives in one place. The five lookup routes that throw 404 by
contract clamp the payload status to 404 explicitly; the index/bulk
write routes that can throw INDEX_NOT_FOUND (404) or
DOCUMENT_LIMIT_REACHED (400) consult the underlying status. The
getSearchIndex post-create check guards against the impossible case
where the service inserted a name that immediately fails lookup —
defensive but unreachable, kept to satisfy the info! exclamation
that upstream relied on.