Diser

Diser task

In general, task of a diser is quite simple. Given request URI and HTTP method, it asks router to find instance of class that will handle the request, build middlewares, passing all relevant information and execute it.

A diser in Fano Framework must implements IDiser interface.

IDiser = interface
    ['{F13A78C0-3A00-4E19-8C84-B6A7A77A3B25}']

    (*!-------------------------------------------
        * dis request
        *--------------------------------------------
        * @param env CGI environment
        * @param stdIn STDIN reader
        * @return response
        *--------------------------------------------*)
    function disRequest(
        const env: ICGIEnvironment;
        const stdIn : IStdIn
    ) : IResponse;
end;
  • env, CGI environment variable that is given by web server. Read CGI Environment for more information.
  • stdIn, object which capable of reading STDIN

Fano Framework will pass instance of CGI environment and IStdIn instance based on protocol that your application use. For example, using CGI or FastCGI protocol, will result different IStdin implementation. However, this should be transparent to developer.

Built-in Diser implementation

Fano Framework comes with several diser implementations.

  • TSimpleDiser is light-weight diser that does not offer middleware layer.
  • TXSimpleDiser is similar to TSimpleDiser with capability to decorate request, response and CGI environment. This is provided, for example, to allow HTTP override _method parameter.
  • TDiser is diser that supports middleware.
  • TXDiser is similar to TDiser with capability like TXSimpleDiser.
  • TMwExecDiser is similar to TXDiser except it makes sure global middlewares are always executed although route does not exist or method verb is not allowed.
  • TMaintenanceModeDiser is decorater diser that makes application enters maintenance mode when a special file exists.
  • TVerbTunnellingDiser is decorator diser that allows web application to serve request through HTTP verb tunnelling.

Creating diser

If you use Fano CLI to scaffold your web application project, you can skip this as Fano CLI creates diser instance for you.

Creating simple diser:

var router : IRouteMatcher;
...
container.add(
    'diser',
    TSimpleDiserFactory.create(
        router,
        TRequestResponseFactory.create()
    )
);

For creating basic diser with middleware support, you need to pass instance of IMiddlewareLinkList instance. Please read Middlewares for more information. container is an instance of IDependencyContainer. Read Dependency Container for more informations.

var router : IRouteMatcher;
...
container.add(
    'diser',
    TDiserFactory.create(
        container.get('appMiddlewares') as IMiddlewareLinkList,
        router,
        TRequestResponseFactory.create()
    )
);

For creating diser with session support, you need to use TSessionDiserFactory as shown in following code. Because session support in Fano Framework is implemented using middleware infrastructure, you also need to pass instance of IMiddlewareLinkList instance. Please read Working with Session for more information.

var router : IRouteMatcher;
...
container.add(
    'diser',
    TSessionDiserFactory.create(
        container.get('appMiddlewares') as IMiddlewareLinkList,
        router,
        TRequestResponseFactory.create(),
        container.get('sessionManager') as ISessionManager,
        (TCookieFactory.create()).domain(config.getString('cookie.domain')),
        config.getInt('cookie.maxAge')
    )
);

To allow HTTP verb tunnelling, wrap actual diser factory with TVerbTunnellingDiserFactory as shown in following code,

container.add(
    'diser',
    TVerbTunnellingDiserFactory.create(
        TSimpleDiserFactory.create(
            router,
            TRequestResponseFactory.create()
        )
    )
);

Maintenance mode

To allow application to enter maintenance mode, use TMaintenanceModeDiser.

var actualDiser : IDiser;
    maintenanceModeDiser : IDiser;
...

maintenanceModeDiser := TMaintenanceModeDiser.create(actualDiser);

To register maintenance mode diser in dependency container, use TMaintenanceModeDiserFactory class.

container.add(
    'diser',
    TMaintenanceModeDiserFactory.create(
        TVerbTunnellingDiserFactory.create(
            TSimpleDiserFactory.create(
                router,
                TRequestResponseFactory.create()
            )
        )
    )
);

By default, this diser checks if file __maintenance__ exists in current directory. If it does then it assumes application is in maintenance mode and raise EServiceUnavailable exception.

To make application enters maintenance mode, create empty file with name __maintenance__ in current working directory. For example

$ touch __maintenance__

To leave maintenance mode, just remove it.

$ rm __maintenance__

To use different filename, set its file path using path() method of TMaintenanceModeDiserFactory().

container.add(
    'diser',
    TMaintenanceModeDiserFactory.create(
        TVerbTunnellingDiserFactory.create(
            TSimpleDiserFactory.create(
                router,
                TRequestResponseFactory.create()
            )
        )
    ).path('/home/example/maintenance')
);

Set diser

Fano Framework allows application to change diser implementation to use, by overriding protected buildDiser() method of TBasicServiceProvider class. In this method implementation, you must returns instance of diser.

function TMyAppServiceProvider.buildDiser(const container : IDependencyContainer) : IDiser;
begin
    result := container['diser'] as IDiser;
end;

If you use Fano CLI to scaffold your web application project, you can declared buildDiser() in bootstrap.pas file as shown in following example.

TAppServiceProvider = class(TDaemonAppServiceProvider)
protected
    function buildDiser(
        const ctnr : IDependencyContainer;
        const routeMatcher : IRouteMatcher;
        const config : IAppConfiguration
    ) : IDiser; override;
    ...
end;
...
function TAppServiceProvider.buildDiser(
    const ctnr : IDependencyContainer;
    const routeMatcher : IRouteMatcher;
    const config : IAppConfiguration
) : IDiser;
begin
    ctnr.add('appMiddlewares', TMiddlewareListFactory.create());

    ctnr.add(
        'my-diser',
        TDiserFactory.create(
            ctnr['appMiddlewares'] as IMiddlewareLinkList,
            routeMatcher,
            TRequestResponseFactory.create()
        )
    );
    result := ctnr['my-diser'] as IDiser;
end;

See example of adding diser with middleware support.

Explore more