CerberusMVC Documentation

Controller


The entrypoint into the system, extended from base controller, the controller offers the usual request in and repsonses out. Requests in are a structured CerberusMVC request, regardless of platform type (aws or express), with responses being either strcutured, unstructured or a promise.

Request Format

Requests are of type cerberus-mvc/System/Request.js and regardless of platform or event type, they appear the same, with flags to help you determine one form the other. An example of this would be AWS, CerberusMVC is capable of accetping requests from API gateway in the form of a client request, or via SQS as an internal message. This helps with things such as automated email bounce blocking when using SES with SQS.

Requests in socket.io controllers are one way! You may respond by emitting an event on the socket directly.

Example incoming request...

{
    context: {
		id: ...,
		ipAddress: ...
	},
    method: ...,
    path: ...,
    access: 'public',
    source: '',
    resource: ...,
    parameters: {
		query: {},
		path: {}
	};
    headers: {},
    body: ...
}

All headers will be in the standard 'Content-Type' and 'Some-Bespoke-Header'.

Response Format

  • Generic data like text, array, object... (auto wraps in a CerberusMVC response and promise for you).
  • Structure response in the from of an object with status, headers and body set (as an object or promise).
  • A promise returning some form of generic data or structured response.

There are no socket.io response objects, just emit directly on the socket to respond.

Example outgoing response...

// Return just the data...
return data;
return 'OK';

// Return a promise...
return Promise.resolve('OK');
return new Promise((res, rej) => ({ some: 'data' }));

// Return structured response, ensure headers are hyphoned 'Capital-Case'
return { status: 200, headers: {'Content-Type': 'application/json'}, body: {foo: 'bar'}};
return Promise.resolve().then(() => ({
	status: 200,
	headers: {'Content-Type': 'application/json'},
	body: {foo: 'bar'}
}));

// Throw new RestError, auto maps to valid response and triggers catch to response conversion...
throw new RestError('Invalid request, could not delete resource', 400);

All headers should be in the standard 'Content-Type' and 'Some-Bespoke-Header'.

CerberusMVC will auto generate a cerberus-mvc/System/Response for you, mapping the repsonse you sent to teh response type required by the provider.

Class

The following code is an example of how we structure a controller (cli tool ships a single health controller for you).

Things to note are imports using require(), extending the base controller, contructor with super call and static getters mirroring rest methods. Static getters allow us to specific access to the methods, these are sniffed out on controller instantiation, passed through to middleware on load. Typical uses for this would be authentication middleware that checks autherization headers for specific endpoints.

Health.js (controller)

'use strict';

const Controller = require('cerberus-mvc/Base/Controller');

/**
 * @namespace API/Controller
 * @class Health
 * @extends Controller
 * @description Controller class exposing methods over the routed endpoint
 * @author Paul Smith (ulsmith)  
 * @copyright 2020 Paul Smith (ulsmith) all rights reserved
 * @license MIT
 */
class Health extends Controller {

	/**
	 * @public @method constructor
	 * @description Base method when instantiating class
	 */
    constructor() {
        super();
    }

	/**
	 * @public @static @get access
	 * @desciption Get the access for methods. All methods are restricted by default unless specifically set as 'public'.
	 * @return {Object} Object of access levels for methods
	 */
    static get get() { return 'public' } // use this as a method to find access level on endpoints from your auth middleware.

    /**
     * @public @method get
     * @description Ping the system to check whats health and whats not
     * @param {*} request The request object that caused the controller to run
     * @return Promise a response promise resolved or rejected with a raw payload or {status: ..., data: ..., headers: ...} payload
     */
	get(request) {
		return {
			name: this.$environment.API_NAME,
			version: this.$environment.API_VERSION,
			mode: this.$environment.API_MODE,
			status: 'healthy',
			dateTime: new Date(),
		};
	}

	/**
	 * @public @static @get access
	 * @desciption Get the access for methods. All methods are restricted by default unless specifically set as 'public'.
	 * @return {Object} Object of access levels for methods
	 */
    static get socket() { return 'public' } // again sockets can use the same middleware! SO restrict your sockets with the same methods

    /**
     * @public @method socket
     * @description Ping the system to check whats health and whats not
     * @param {*} request The request object that caused the controller to run
     * @return Promise a response promise resolved or rejected with a raw payload or {status: ..., data: ..., headers: ...} payload
     */
	socket(request) {
		// Do not return... we do not send a respond to sockets, we emit them when required.

        // Examples of emitting events to clients, please consult socket.io cheatsheet for more
        // You can access $ variables from any cerberus-mvc extended class, such as middleware and services too.
        
        this.$socket.emit('log', 'me only\n', 34, {test: 'fsdfsdfsd'});
		this.$io.emit('log', 'everyone\n');
		this.$socket.broadcast.emit('log', 'not me\n');
	}
}

module.exports = Health;