Resources + errors
Two small primitives shape the surface a route presents to its callers: defineResource declares the public shape of a response; defineError makes thrown errors typed + status-tagged.
defineResource
(unchanged — see the reference for the full surface and the HTTP routes guide for how it plugs into a route handler.)
The public field list is the allowlist. Internal fields never leak. Studio's OpenAPI spec uses the public projection.
defineError
defineError(meta) returns a value that is both an Error instance you can throw directly and a callable factory that produces a contextual clone:
import { defineError } from "@nwire/handler";
export const UserNotFound = defineError({
code: "USER_NOT_FOUND",
status: 404,
summary: "No user found with that id.",
});
export const EmailAlreadyTaken = defineError({
code: "EMAIL_ALREADY_TAKEN",
status: 409,
summary: "That email is registered to another account.",
});Throw with context — the callable form attaches the context to the thrown clone:
if (!user) throw UserNotFound({ userId: input.id });
if (existing) throw EmailAlreadyTaken({ email: input.email });Throw without context — the definition itself is an Error:
throw UserNotFound;The HTTP adapter's top-level error mapper reads code, status, and summary and emits a structured envelope:
{
"error": {
"code": "USER_NOT_FOUND",
"summary": "No user found with that id."
}
}Throws that don't carry a code + status become a generic { code: "internal_error", status: 500 } envelope; the adapter logs the original server-side and sends the client nothing else. This protects against accidental leaks of driver errors, raw stack traces, or PII attached to a thrown Error. httpKoa({ exposeErrors: true }) echoes the real message for local debugging — off by default in every environment. The same mapper answers wired routes, Studio's POST /_nwire/dispatch, and MCP's dispatch_action; see the error contract.
Built-in errors
@nwire/handler ships the common HTTP errors as defineError instances:
import {
Unauthorized, // 401
Forbidden, // 403
NotFound, // 404
Conflict, // 409
Gone, // 410
BadRequest, // 400
} from "@nwire/handler";
throw Unauthorized;
throw Forbidden({ resource: "post", id: input.postId });
throw NotFound({ resource: "user", id: input.id });@nwire/errors re-exports these for compatibility with older imports; new code should import from @nwire/handler.
Where to next
defineResourcereference — projection helpers, OpenAPI schema emission.defineErrorreference — custom error types, status mapping.- HTTP routes — where the error middleware lives in the request pipeline.