Lifecycle Hooks
Use before, after, and onError hooks for logging, metrics, and centralized error handling.
Hooks are shared interception points around route execution.
Why they exist:
- keep handlers focused on business logic
- centralize logging, metrics, and error policy
- avoid copy/pasting cross-cutting concerns into every route
Global hooks
Configure once in createWebhookRouter options:
import { createWebhookRouter } from "@zap-studio/webhooks";
const router = createWebhookRouter({
before: (req) => {
console.log("incoming", req.path);
},
after: (_req, res) => {
console.log("status", res.status);
},
onError: (error) => ({
status: 500,
body: { error: error.message },
}),
});Route-level hooks
Route hooks are useful when one endpoint needs extra behavior beyond global hooks.
import { z } from "zod";
router.register("github/push", {
schema: z.object({ ref: z.string() }),
before: (req) => {
console.log("route-before", req.path);
},
handler: async ({ ack }) => ack({ status: 200 }),
after: (_req, res) => {
console.log("route-after", res.status);
},
});Hook order
Understanding order matters when composing observability and validation behavior.
For successful requests:
- global
before - route
before verify- validation
- handler
- route
after - global
after
For errors:
onErroris called and may return a custom response.
Why onError returns a response:
- gives you one place to standardize error shape/status
- lets you map provider/framework errors consistently
Edit on GitHub
Last updated on