NODERYX
FRAMEWORK v0.7.1

GETTING STARTED

BUILDING

PRODUCTION

DEVICES

REFERENCE

NODERYX / DOCS / BUILDING / 02
BUILDING / 02

Routing & controllers

How a request becomes a response: routes, parameters, the request context, controllers, middleware, and errors.

01

Register routes

The application exposes get, post, put, and delete. Each takes a path and a handler, and each returns the app so calls can be chained.

server.js
app.get("/posts", handler); app.post("/posts", handler); app.put("/posts/:id", handler); app.delete("/posts/:id", handler);
NOTE

Register your application routes before loadPackages() so a package cannot shadow one of your paths.

02

Path parameters and query strings

A :name segment becomes params.name. The query string is parsed into a plain object, so no helper is needed to read it.

server.js
app.get("/users/:id", ({ params, query, json }) => { return json({ id: params.id, page: query.page ?? "1" }); });
03

The request context

Every handler receives one object. It carries the request, parsed input, session state, and the helpers that produce a response.

params, query, body Route parameters, parsed query string, parsed request body.
render(view, data, status) Compile a Noderframe view and send HTML.
json(data, status) Send JSON—or a readable viewer when a browser asks for HTML.
text(value, status, type) Send plain text or a custom content type.
abort(status, message) Throw an HttpError handled by the error pages.
session Signed, stateless session store. Mutating it re-issues the cookie.
validate(rules) Validate the body and return { valid, values, errors }.
service(name) Resolve a service registered with app.provide().
csrfToken, nonce, ip, cookies Per-request values for forms, inline scripts, limiting, and cookies.
setCookie / clearCookie Queue cookies onto the response.
04

Move logic into controllers

A controller groups the actions of one resource. Controller.handle("action") returns a route handler, and the instance exposes the context through named getters.

app/Controllers/PostController.js
import { Controller } from "noderyx-framework"; export class PostController extends Controller { async index() { return this.json(await Post.all()); } async show() { const post = await Post.find(this.params.id); if (!post) return this.abort(404, "That post does not exist"); return this.render("posts/show", { post }); } }
05

…and route them

handle() is a static factory, so each request gets its own controller instance and no state leaks between requests.

server.js
app.get("/posts", PostController.handle("index")); app.get("/posts/:id", PostController.handle("show")); app.post("/posts", PostController.handle("store"));
NOTE

Generate the class with npx noderyx make:controller PostController.

06

Controller helpers

Controllers expose the context through a small, predictable surface.

this.request The raw Node.js request.
this.params / this.query / this.body Parsed input.
this.json(data, status) JSON response.
this.text(value, status, type) Text response.
this.render(view, data, status) HTML response from a view.
this.abort(status, message) Stop with an HTTP error.
this.service(name) Resolve a registered service, such as ai.
07

Middleware

Middleware wraps every request. Register a function with app.use(), or generate a class with an async handle(context, next) method and register its handler.

server.js
app.use(async (context, next) => { const started = Date.now(); await next(); console.log(`${context.request.method} ${context.request.url} ${Date.now() - started}ms`); });
NOTE

Middleware runs in registration order. Call next() exactly once, and return early to short-circuit.

08

Errors

abort() throws an HttpError that the framework turns into the matching error view, with a JSON body when the client asked for JSON. Unexpected exceptions become a 500 and, in development, a debug page that explains the likely cause.

server.js
app.get("/admin", ({ session, abort, render }) => { if (!session.userId) return abort(401); if (!session.isAdmin) return abort(403, "Administrators only"); return render("admin/index"); });
NOTE

Only messages you pass to abort() are shown to users. Internal error messages and stack traces stay hidden outside development.

09

Services

app.provide(name, value) registers a dependency once; handlers and controllers resolve it with service(name). This is how the AI client is wired, and it is the right place for a database connection, a mailer, or a queue client.

server.js
const db = await connect(config.database); app.provide("db", db); app.provide("ai", ai(config.ai)); app.get("/stats", async ({ service, json }) => { const rows = await service("db").query("SELECT count(*) FROM users"); return json(rows); });
NOTE

Resolving a name that was never registered throws immediately, so a typo fails at the first request rather than silently returning undefined.

10

Static files and health

Anything in public/ is served under /public with content types, ETags, compression, and production caching. Generated projects also expose a health route, which is what live reload and most deployment platforms poll.

server.js
app.get("/health", HomeController.handle("health")); // {"status":"ok","runtime":"Node.js"}