Skip to Content

ApiReturn(label, statusCode, body)

For handlers registered as Express api endpoints (see Cat modes), ApiReturn records the HTTP status and body shape for QA, emits an API_RESPONSE inspector event, and returns a plain object for your handler to pass to Express.

Signature

function ApiReturn<L extends string, T>( label: L, statusCode: number, body: T, ): ApiPayload<T> interface ApiPayload<T> { statusCode: number body: T }

Usage

ApiReturn returns { statusCode, body } so you can wire the same object into Express without duplicating status or payload:

import { ApiReturn, Cat, registerCatPipeline } from '@gloocan/cat-inspector' import express, { type Request, type Response } from 'express' class OrderController { @Cat create(req: Request, res: Response): void { const dto = buildOrderDto(req.body) const r = ApiReturn('CREATED', 201, { ok: true, order: dto }) res.status(r.statusCode).json(r.body) } } const router = express.Router() registerCatPipeline(router, 'post', '/orders', [ new OrderController().create.bind(new OrderController()), ])

Use different labels for each documented response shape (success, auth failure, validation). The QA catalog and AST scan pick up labels from ApiReturn('LABEL', …) in the handler body:

import { ApiReturn, cat, registerCatPipeline } from '@gloocan/cat-inspector' import express, { type NextFunction, type Request, type Response } from 'express' const requireSession = cat('Auth.requireSession', function requireSession( req: Request, res: Response, next: NextFunction, ): void { if (!req.header('x-session')) { const r = ApiReturn('UNAUTHORIZED', 401, { error: 'missing session' }) res.status(r.statusCode).json(r.body) return } next() }) const trigger = cat('Workflow.trigger', function trigger(req: Request, res: Response): void { if (!req.body?.origin) { const r = ApiReturn('VALIDATION_FAILED', 422, { issues: [{ path: 'origin', message: 'required' }], }) res.status(r.statusCode).json(r.body) return } const r = ApiReturn('OK', 200, { ok: true, timeline: buildTimeline(req.body) }) res.status(r.statusCode).json(r.body) }) const router = express.Router() registerCatPipeline(router, 'post', '/trigger', [requireSession, trigger])

The same ApiReturn('LABEL', status, body) call works inside cat() or catModule handlers registered on a pipeline — labels are discovered from the source for the catalog whether you use @Cat or cat.

For normal RPC handlers (not Express api mode), use Return instead — ApiReturn is only for HTTP pipeline endpoints where the last handler is mode: 'api'.

Error bodies and the QA pipeline

The SDK does not require specific body keys — you choose the JSON shape. The QA pipeline (frontend) looks for two optional conventions on API_RESPONSE bodies and on HTTP step responses so operators can see problems quickly.

error (string)

Use for a single human-readable message (auth failures, business errors, generic failures):

ApiReturn('UNAUTHORIZED', 401, { error: 'missing session' })

Pipeline behavior:

  • HTTP trace — subtitle includes the string; if status matches the scenario’s expected status but error is present, the step may show warn instead of pass.
  • Inspector event list — red error styling when the body has an error key or statusCode >= 400; caption appends · <message> from body.error.
  • JSON preview — highlights the "error" key in the response body.
  • HTTP status assert (expected status mismatch) — prefers error when building failure detail (error: …).

issues (array)

Use for field-level validation (same item shape the pipeline already understands):

ApiReturn('VALIDATION_FAILED', 422, { issues: [{ path: 'origin', message: 'required' }], })

Each item should be { path: string, message: string }. The UI summarizes up to three entries as path message; … in the trace subtitle.

Pipeline behavior:

  • HTTP trace — subtitle uses the summarized issues text (checked after error if both exist).
  • Inspector event listissues alone does not trigger the red “inspector error” icon; 4xx/5xx status still does.
  • HTTP status assert — if there is no string error, failure detail falls back to summarized issues, then plain message on the body.

There is no issue key — use issues (plural).

Quick reference

Body shapeTrace subtitleRed error icon in HTTP listTypical status
{ error: "…" }YesYes (even on 2xx)401, 403, 400, …
{ issues: [{ path, message }] }YesOnly if status ≥ 400422
Success payload onlyLabel + statusNo200, 201, …

Suggested patterns

ScenarioLabel exampleStatusBody
Auth / permissionUNAUTHORIZED401{ error: "…" }
ValidationVALIDATION_FAILED422{ issues: [{ path, message }] }
SuccessOK, CREATED200 / 201{ ok: true, … }

You can combine keys or use other fields in the body for your API contract; only error and issues get special treatment in the pipeline UI. Match what your real HTTP clients return so QA runs read the same way production responses do.

Context requirement

ApiReturn uses the active API context (fnKey of the pipeline endpoint). That context is set by the Express integration when the final pipeline handler runs (registerCatPipeline). Outside that context, the call is effectively a no-op for inspector metadata (still returns { statusCode, body }).

Types

Labeled<L, T> is exported for typing branded labels when needed.

See also