MasterController

Controllers

Plain ESM classes that turn requests into responses.

Controllers live in app/controllers/. Each request constructs a fresh instance and calls the action method named in the route. Actions receive the request object and reply with one of the response helpers.

Anatomy of a controller#

postsController.js
import db from '../models/db.js';

export default class PostsController {
  constructor(requestObject) {
    this.requestObject = requestObject;
  }

  // GET /posts
  async index() {
    const data = await db.Post.toList();
    this.returnJson({ data });
  }

  // POST /posts
  async create(obj) {
    const post = db.Post.new();
    Object.assign(post, obj.params.formData || {});
    await post.save();
    this.returnJson({ data: post });
  }

  // GET /posts/:id
  async show(obj) {
    const post = await db.Post.where((p) => p.id == $$, Number(obj.params.id)).single();
    if (!post) return this.returnError(404, 'Not found');
    this.returnJson({ data: post });
  }
}

Response helpers#

MethodEffect
this.returnJson(data)Send JSON (200, or data.status if 4xx/5xx).
this.returnError(code, msg, details?)Send a structured JSON error.
this.returnView(data)Render the action’s view (needs a view engine).
this.returnPartialView(view, data)Render a partial without a layout.
this.redirectTo(path)Redirect (same-origin validated).
this.redirectBack(fallback?)Redirect to the referer, or a fallback.
It's returnJson, not json
The response methods are returnJson, returnError, returnView, and redirectTo — there is no this.json() or this.render().

Accessing request data#

request-data.js
async show(obj) {
  const id = obj.params.id;             // route parameter (casing preserved)
  const q = obj.params.query.search;     // ?search=...
  const body = obj.params.formData;      // parsed JSON / form body
  const method = obj.type;               // 'get' | 'post' | ...
  const req = obj.request;               // raw Node request
  const res = obj.response;              // raw Node response
}
Note
For application/json requests, the parsed body is available as obj.params.formData. Multipart uploads expose obj.params.formData.files.

Per-request state#

Each instance gets this.state (shared with middleware) plus this.__request, this.__response, and the route context — set on the instance, never the prototype, for concurrency safety.