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

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 SearchRouteEvent discriminated union so emissions never need as any and consumers can pattern-match on event.type.
  • Typed errors mapped to HTTP via errorPayload: SearchError with context.statusCode === 404 maps to 404, every other failure to 400; non-SearchError throwables stringify their message.
  • Side-effect-free factory — createSearchRoutes builds 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.