Skip to content

defineError

defineError(name, options) declares a typed throwable error with an HTTP status code and an optional Zod payload schema. The HTTP error middleware envelopes thrown instances into structured JSON responses.

Signature

ts
import { defineError } from "@nwire/handler";

function defineError<TSchema extends ZodTypeAny>(
  name: string,
  options: {
    status: number;
    schema?: TSchema;
  },
): ErrorDefinition<TSchema>;

Example

ts
import { defineError } from "@nwire/handler";
import { z } from "zod";

export const UserNotFound = defineError("UserNotFound", {
  status: 404,
  schema: z.object({ userId: z.string() }),
});

export const EmailAlreadyTaken = defineError("EmailAlreadyTaken", {
  status: 409,
  schema: z.object({ email: z.string() }),
});

Throwing

ts
async ({ input, resolve }) => {
  const user = await resolve<UserStore>("users").get(input.id);
  if (!user) throw UserNotFound({ userId: input.id });
  return user;
}

The constructor accepts the payload schema's input shape. The middleware serializes the error as:

json
{
  "error": "UserNotFound",
  "status": 404,
  "details": { "userId": "abc" }
}

Built-in errors

@nwire/handler ships the common HTTP errors so you don't have to declare your own for the standard cases:

ClassStatus
Unauthorized401
Forbidden403
NotFound404
Conflict409
Gone410
BadRequest400
UnprocessableEntity422
TooManyRequests429
InternalServerError500
ts
import { Unauthorized, NotFound, Conflict } from "@nwire/handler";

throw new Unauthorized("missing token");
throw new NotFound("user", input.id);
throw new Conflict("email already taken");

OpenAPI integration

Errors a route may throw can be declared in the route's openapi metadata:

ts
.wire(
  get("/users/:id", {
    params: z.object({ id: z.string() }),
    openapi: { throws: [UserNotFound] },
  }),
  handler,
)

The operation declares a 404 response with UserNotFound's shape; clients codegenning against the spec see the typed error.

See also

MIT licensed.