Skip to content

Cell - MVC Component ​

Controllers for Cell backends: classes with @Controller whose methods answer HTTP requests. It runs on @celljs/web (node:http, no express). Guide: HTTP APIs.

bash
npm install @celljs/mvc @celljs/express-adapter

@celljs/express-adapter is the backend entry that starts the server; the cell init templates already depend on both.

ts
import { Body, Controller, Get, Param, Post } from '@celljs/mvc/lib/node';

@Controller('users')
export class UserController {
    @Get(':id')
    get(@Param('id') id: number) {
        return { id };                       // JSON
    }

    @Post()
    create(@Body() user: { name: string }) {
        return user;
    }
}

Import the controller's file from the DI module (src/node/module.ts), or it is not loaded.

Routes ​

Decorator
@Controller(path?)A component (singleton, proxied for AOP) whose methods are routes under path. Also takes ComponentOptions: @Controller({ path: 'users', rebind: true })
@Get, @Post, @Put, @Patch, @Delete, @Head, @OptionsOne HTTP method; the argument is the path under the controller (':id'), empty for the controller path
@All(path?)Every method

Path syntax: :name is one segment, * matches anything, (...) is optional. Routes are mounted under server.path (default /); mvc.path (default /*) is the pattern of requests the MVC handler takes. A request that matches no route gets 404 with the method and path in the message.

Parameters ​

DecoratorValue
@Param(name?)A path parameter, or all of them
@Query(name?)A query parameter, or the whole parsed query
@Body(name?)A field of the parsed body, or the whole body
@Header(name?)A request header, or all headers
@Cookie(name?)A request cookie
@Session(name?)A session value
@Req() / @Res()The request / response objects of @celljs/web

Parameters typed String, Number, Boolean or Date are converted. Parameters typed with a class are validated when @celljs/validation is installed.

Responses ​

DecoratorResponse
none or @Json()The return value as JSON (mvc.defaultViewName: json)
@Text()The return value as text/plain
@Html(template?)A Mustache template rendered with the return value (see below)
@File(file?)A Buffer or stream returned by the method, or the file file in mvc.baseFileDir (default assets, relative to the directory of the server code)
@View(name, metadata?)A view by name; add views by binding View
@Header(name, value)Sets a response header
@Cookie(name, value)Sets a response cookie
@Session(name, value)Stores a value in the session

A method may be async. Returning undefined answers 200 with an empty body. Set another status on the response (@Res() res, res.statusCode = 201) and return the body as usual.

mvc.jsonView.template wraps every JSON response and error in a template, for APIs that answer { "success": ..., "data": ... }: {{model}} (JSON, null when there is none), {{error}}, {{success}} and {{code}} are replaced, every occurrence; {{error}} and {{code}} are escaped for a JSON string, so write them inside quotes.

Errors ​

Throw HttpError(status, message) or a subclass such as NotFoundError from @celljs/web/lib/node to answer with that status; other errors answer 500. Stack traces are not sent. The error handlers of @celljs/web answer with the message ErrorMessageResolver allows: in production a server error gives only its status text (web.errors.exposeMessages changes it). With mvc.jsonView.template, JsonViewErrorHandler (priority 2000) answers every error with the template instead and keeps the status of the response.

@Catch(ErrorType | ErrorType[]) on a method of the controller handles the errors of those types thrown by its routes; the method gets the error and its return value is the response:

ts
@Catch(QuotaError)
@Text()
onQuota(err: QuotaError) {
    return `handled: ${err.message}`;
}

Application-wide error handling is an ErrorHandler of @celljs/web.

HTML views ​

@Html('page.mustache') renders a template from mvc.mustache.baseViewDir (default assets/views) with the value the method returns. mvc.mustache.cache: true keeps compiled templates in memory.

Templates use the Mustache syntax, without a third-party engine:

  • {{name}} writes a value HTML-escaped, {{{name}}} or {{& name}} as it is; user.name reads a path, . is the current item;
  • {{#list}}...{{/list}} repeats for each item, enters an object, or shows when the value is truthy; {{^list}}...{{/list}} shows when it is falsy or empty;
  • {{! comment }} writes nothing.

Partials ({{> name}}) and other delimiters ({{=<% %>=}}) are not supported: such a template fails when it is compiled.