A minimal Node.js/TypeScript backend framework. A route's shape, validation, and handler live in one call: give it a schema, get a typed context and a runtime check. Handlers are async functions that take a typed context and return a plain value, which becomes the JSON response. No req/res/next, no external HTTP library, no validation library just node:http and a small hand-rolled validator.
npm install @cairnjs/coreimport { cairn } from '@cairnjs/core';
const app = cairn();
app.route('GET /users/:id', {
params: { id: 'string' },
handler: ({ params }) => ({ id: params.id, name: 'Ada Lovelace' }),
});
app.route('POST /users', {
body: { name: 'string', age: 'number?' },
handler: ({ body }) => ({ created: true, ...body }),
});
app.listen(3000);Returns an app instance.
pattern is "METHOD /path/:param", e.g. "GET /users/:id".
def:
| field | type | description |
|---|---|---|
params |
schema | validated + coerced from URL params |
query |
schema | validated + coerced from query string |
body |
schema | validated from parsed JSON body |
before |
BeforeHook | BeforeHook[] |
route-scoped hooks, run before validation |
handler |
(ctx) => value | Promise<value> |
return value becomes the JSON response |
The schema mini-language is 'string' | 'number' | 'boolean', with a trailing ? for optional. The same schema drives the TypeScript type of ctx.params / ctx.query / ctx.body.
Plugins are functions that receive the app instance:
app.use((app) => {
app.before((ctx) => {
console.log(`${ctx.method} ${ctx.path}`);
});
});Register a global hook that runs before the handler, receiving a mutable ctx. A hook may return an "after" callback that runs once the handler completes.
Returns a typed error. Throw it in a handler or hook to produce a JSON error response with that status:
throw app.error(404, 'not found');Returns a redirect value. Return it from a handler to respond with a 302 + Location header.
Starts a node:http server. Returns the server.
@cairnjs/plugin-examplelogger.app.use(loggerPlugin()).@cairnjs/plugin-authroute-scoped auth guard.before: [authGuard({ key })].
examples/basic-apiminimal CRUD-ish app with the logger plugin.examples/url-shortenera URL shortener dogfooding the framework, with a friction log.
See CONTRIBUTING.md.
See SECURITY.md.
MIT. See LICENSE.
