Getting Started
Following document explains minimum steps required to setup a working Fano web application on development machine.
Requirement
- Linux or FreeBSD
- Free Pascal >= 3.0
- git
- Fano CLI. Read Installation section of Scaffolding with Fano CLI documentation for more information.
- Working Internet connection.
Create application
Make sure all requirements above are met. Run
$ fanocli --project-http=Hello
$ cd Hello
$ fanocli --controller=Home --route=/
$ ./build.sh
$ ./bin/app.cgi
Run it from browser
Open web browser and go to http://localhost:20477
. You should see Home controller
text is printed in browser. Congratulations, your application is working.
Following video shows step by step creating HTTP web application project.
Command walkthrough
Let us take a look at each command above to understand what it does.
Following command tells Fano CLI to create http web application project in Hello
directory. Directory must not exist. Read Creating Project with Fano CLI for creating different web application project (CGI, FastCGI, SCGI, uwsgi or http).
$ fanocli --project-http=Hello
We change active directory to newly created Hello
directory.
$ cd Hello
Create controller name HomeController.pas
that will handle request to route /
. For more information regarding route, read Working with Router.
$ fanocli --controller=Home --route=/
Without --route=/
, by default, Fano CLI will create route same as lower case of controller’s name, i.e, /home
. If you omit --route=/
then you can only access HomeController
using URL http://localhost:20477/home
instead of http://localhost:20477
.
Compile application
$ ./build.sh
Run application
$ ./bin/app.cgi
By default, generated executable will have name app.cgi
inside bin
directory.
Project directory walkthrough
Fano Framework has no opinion about your project directory structure. You can structure your project directories and files the way you like. However, Fano CLI creates several files and directories that follows certain assumptions.
Directories
src
, application project source code directorybin
, compiled binaries output directory,config
, application configuration directoryresources
, application resources directory, such as HTML templates, SCSS, etc.storages
, application runtime-generated files directory, such as session files, logs etc.tools
, helper shell scripts directory, such as scripts to clean compiled binaries.public
, application document root directory where public resources resides such as images, cascade stylesheets, JavaScripts files.
Files
- Main program source code is
src/app.pas
. - Main unit
src/bootstrap.pas
glues all modules. - Home controller
HomeController.pas
insrc/App/Home/Controllers
is code that printsHome controller
text. - Include file
src/Routes/Home/route.inc
associates default URL/
with home controller. - Include file
controllers.dependencies.inc
insrc/Dependencies
directory, registers factory class for home controller.
src/app.pas
This is typical main program source code of web application which is generated by Fano CLI (comments are omitted for brevity).
program app;
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
sysutils,
fano,
bootstrap;
var
appInstance : IWebApplication;
cliParams : ICliParams;
svrConfig : TFpwebSvrConfig;
begin
cliParams := (TGetOptsParams.create() as ICliParamsFactory)
.addOption('host', 1)
.addOption('port', 1)
.build();
svrConfig.host := cliParams.getOption('host', '127.0.0.1');
svrConfig.port := cliParams.getOption('port', 20477);
writeln('Starting application at ', svrConfig.host, ':', svrConfig.port);
svrConfig.documentRoot := getCurrentDir() + '/public';
svrConfig.serverName := 'http.fano';
svrConfig.serverAdmin := 'admin@http.fano';
svrConfig.serverSoftware := 'Fano Framework Web App';
svrConfig.timeout := 120;
//uncomment following lines support https
//svrConfig.useTLS := true;
//svrConfig.tlsKey := '/path/to/ssl/cert/key';
//svrConfig.tlsCert := '/path/to/ssl/cert/cert';
appInstance := TDaemonWebApplication.create(
TFpwebAppServiceProvider.create(
TAppServiceProvider.create(),
svrConfig
),
TAppRoutes.create()
);
appInstance.run();
end.
Main program creates web application instance and service provider instances to build all services that your application required and then run it.
TDaemonWebApplication
and TFpWebAppServiceProvider
are built-in classes provided by Fano Framework to support
creation of long-running http web application that uses Free Pascal Fpweb http server library.
Depending on parameter you use for creating project with Fano CLI, it may end up using TIndyAppServiceProvider
, TMhdAppServiceProvider
, TFastCgiAppServiceProvider
, TScgiAppServiceProvider
, TUwsgiAppServiceProvider
for http web application based on Indy http server, libmicrohttpd http server, FastCGI, SCGI, uwsgi web application respectively.
TAppServiceProvider
and TAppRoutes
are two classes that specific to your application which are responsible for creating all services and routes required by your application. Both are declared in unit bootstrap.pas
src/bootstrap.pas
This typical file is generated by Fano CLI (comments are omitted for brevity) to allow application to initialize all services and routes it requires.
unit bootstrap;
interface
uses
fano;
type
TAppServiceProvider = class(TDaemonAppServiceProvider)
protected
public
procedure register(const container : IDependencyContainer); override;
end;
TAppRoutes = class(TRouteBuilder)
public
procedure buildRoutes(
const container : IDependencyContainer;
const router : IRouter
); override;
end;
implementation
uses
sysutils,
HomeControllerFactory;
procedure TAppServiceProvider.register(const container : IDependencyContainer);
begin
{$INCLUDE Dependencies/dependencies.inc}
end;
procedure TAppRoutes.buildRoutes(
const container : IDependencyContainer;
const router : IRouter
);
begin
{$INCLUDE Routes/routes.inc}
end;
end.
TAppServiceProvider
is class implements IServiceProvider
interface which has
one method name register()
. It will be invoked by Fano Framework during intialization and will receive
instance of dependency container. In this method, you initialize all services required by your application. TAppServiceProvider
inherits from TDaemonAppServiceProvider
which setups common
services for long-running web application.
TAppRoutes
is class implements IRouteBuilder
interface which has one method buildRoutes()
to implements.
It inherits from TRouteBuilder
, an abstract class implements this interface.
Application builds routes in buildRoutes()
method.
To simplify creating this file, Fano CLI uses two main include files dependencies.inc
and routes.inc
.
src/Dependencies/dependencies.inc
Following snippets shows typical content of this file (comments are ommited for brevity). Each lines are include files specific for certain purpose.
{$INCLUDE main.dependencies.inc}
{$INCLUDE middlewares.dependencies.inc}
{$INCLUDE models.dependencies.inc}
{$INCLUDE views.dependencies.inc}
{$INCLUDE controllers.dependencies.inc}
For example in controllers.dependencies.inc
you may have following code
container.add('homeController', THomeControllerFactory.create());
which register factory class for home controller using key homeController
.
src/Routes/routes.inc
This is typical routes file generated by Fano CLI as shown below.
{$INCLUDE Home/routes.inc}
Which in turns include other files. For example src/Routes/Home/routes.inc
may have
following code.
router.get('/', container.get('homeController') as IRequestHandler);
Above code registers route /
with GET method to instance of home controller.
src/App/Home/Controllers/HomeController.pas
This typical controller code generated by Fano CLI (comments are omitted for brevity).
It inherits from TAbstractController
which is an abstract class implements IRequestHandler
interface that has one method handleRequest()
.
unit HomeController;
interface
{$MODE OBJFPC}
{$H+}
uses
fano;
type
THomeController = class(TAbstractController)
public
function handleRequest(
const request : IRequest;
const response : IResponse;
const args : IRouteArgsReader
) : IResponse; override;
end;
implementation
function THomeController.handleRequest(
const request : IRequest;
const response : IResponse;
const args : IRouteArgsReader
) : IResponse;
begin
response.body().write('Home controller');
result := response;
end;
end.
When Internet browser request routes /
, handleRequest()
method is invoked which prints Home controller
in browser.
handleRequest()
method receives request, response and route argument instance you can use,
for example, to read query string parameter.