Principles
The design principles behind Zen Router.
Zen Router is an opinionated router. These are the principles that underlie its API design.
Pragmatic
- Implementing real-world endpoints should be joyful, easy, and type-safe.
- All requests and responses are JSON by default. For convenience, you can
directly return a JSON value and it will be turned into a proper JSON
Responsewith the correct headers. - You can throw any HTTP error to short-circuit a non-2xx response.
- JSON error responses for all common HTTP status codes, customizable per status code.
- All error responses have at least an
{ error }key with a human-readable string. - CORS support is built-in with a sane
{ cors: true }default that applies to all endpoints in the router.OPTIONSroutes and responses are managed automatically.
Secure by default
- All requests must be authorized. Authorization is opt-out, not opt-in.
- All path params are verified and type-safe (
/foo/<bar>/<qux>available asp.barandp.qux), cannot be empty, and are URI-decoded automatically. - Incoming JSON request bodies must be validated, and are made available as
a fully type-safe
bodyin the handler. - All query strings are type-safely accessible (
/foo?abc=hiasq.abc).
Maintainable
- All route patterns are fully qualified, and thus greppable. No "base" prefix URL setup, which in practice makes codebases harder to navigate over time.
- Routes always include the method in their definition, so
"POST /api/posts"instead of.post("/api/posts"). There is no such thing as.all("/api/posts"). - No middlewares. Middlewares are easy to bolt on but get harder to trace
in large codebases over time: which ones are active, what do they do, what
did they attach to the request object? Zen Router replaces all of that with
a single request context (
ctx) that carries data alongside a request. Figuring out where contextual data comes from is one "Jump to definition" away. - No fall-through. Once a route handler runs, it must return a response. It never silently falls through to another handler. The same applies to composed routers.
- Default error handling is configurable per status code; individual handlers can always bypass it by throwing a custom Response.
- If you return a JSON value from your handler directly, it must be an object, not an array. We do this to encourage building extensible responses by default.