Controllers

The role of the controller is to generate a response to a request.

The most basic controller simply returns a static response:

export class MyController implements IController
{
    public handle(request: IncomingMessage): MaybePromise<IResponse>
    {
        return new StringResponse('Hello World');
    }
}

You can also access the url query parameter:

export class MyController implements IController
{
    public handle(request: IncomingMessage): MaybePromise<IResponse>
    {
        if ('q' in this.query)
        {
            return new StringResponse('You searched for: ' + this.query['q']);
        }
        return new StringResponse('Missing query parameter "q"');
    }
}

In most cases controllers will be bound to routes.

@Route({
    // the default method is 'get'
    method: 'get',
    route: '/my/path'
})
export class MyController implements IController
{
    public handle(request: IncomingMessage): MaybePromise<IResponse>
    {
        return new StringResponse('Hello World');
    }
}

The same controller can be bound to any number of routes and you can read the requested URL from request.url.

Routes can also be dynamic and in that case the dynamic parts will be set in the props property.

@Route({
    route: '/my/path/:category/:name'
})
export class MyController implements IController
{
    public handle(request: IncomingMessage): MaybePromise<IResponse>
    {
        // in case of url: /my/path/event/my-party
        this.props.category === 'event'
        this.props.name === 'my-party'
    }
}

If the route has no dynamic parts then the props property will be undefined.

You can learn more about routing here.

Base controller classes

To present a HTML page we would create a Renderable element and returning it in a RenderResponse.

export class MyPageController implements IController
{
    @Dependency
    private container: ISrviceContainer;

    public handle(request: IncomingMessage): MaybePromise<IResponse>
    {
        const renderable = this.container.create(Renderable, 'my-template-name');
        return this.container.create(RenderResponse, renderable);
    }
}

PageController was introduced to make this easier.

export class MyPageController extends PageController
{
    public page(request)
    {
        return this.container.create(Renderable, 'my-template-name');
    }
}

In case of post and put requests you will also have access to request body.
You can select an appropriate base class based on the type of data you're handling.

If you're developing an API endpoint you should use the JsonController.

export class MyApiController extends JsonController
{
    public handleJson(request, json)
    {
        return new JsonResponse({ status: 'OK' });
    }
}

If you are handling a HTML form you should use the FormController.

export class MyFormController extends FormController
{
    public handleForm(request, form)
    {
        return new RedirectResponse('/back/to/previous/page');
    }
}

The FormPageController was specially created for controllers that handle both displaying a page and handling form data.

export class MyFormPageController extends FormPageController
{
    public page(request, form?, error?: string)
    {
        return this.container.create(Renderable, 'my-template-name');
    }
}

In case of post and put requests you would either get the form or error argument depending on whether form data was successfully parsed or not.

Previous article

Configuration

Next article

Responses