Simplifying the usage of ModularBr with desktop applications through middleware.
ModularBr is a versatile framework that goes beyond its integration with REST frameworks for building RESTful APIs. It is also well-suited for client/server (desktop) project development. With its dependency injection and bind exporting functionalities, ModularBr provides a modular approach to Delphi application development. This approach can be applied to projects involving client-server communication, allowing developers to benefit from the modularity, code reuse, and dependency management offered by ModularBr. By adopting ModularBr in client/server projects, developers can enhance code organization, simplify maintenance, and facilitate scalability of desktop applications.
Just as in RESTful applications, in desktop applications, the AppModule also plays a crucial role as the entry point for utilizing ModularBr.
uses
dmfbr.modular,
...
procedure TFormPing.PingClick(Sender: TObject);
var
LRouteHandler: TPingRouteHandler;
begin
LRouteHandler := TPingRouteHandler.Create;
try
ShowMessage(LRouteHandler.Ping);
finally
LRouteHandler.Free;
end;
end;
procedure TFormPing.FormCreate(Sender: TObject);
begin
Modular.Start(TAppModule.Create);
end;
In the AppModule, we define the initial routes.
...
function TAppModule.Routes: TRoutes;
begin
Result := [RouteModule('/ping', TPingModule)];
end;
We define the module for the mapped route '/ping'.
unit ping.module;
interface
uses
ping.controller,
ping.service,
dmfbr.module;
type
TPingModule = class(TModule)
public
function Imports: TImports; override;
function Binds: TBinds; override;
function Routes: TRoutes; override;
function RouteHandlers: TRouteHandlers; override;
function ExportedBinds: TExportedBinds; override;
end;
implementation
{ TPingModule }
function TPingModule.Binds: TBinds;
begin
Result := [Bind<TPingService>.Factory,
Bind<TPingController>.Singleton];
end;
function TPingModule.ExportedBinds: TExportedBinds;
begin
Result := [];
end;
function TPingModule.Imports: TImports;
begin
Result := [];
end;
function TPingModule.RouteHandlers: TRouteHandlers;
begin
Result := [];
end;
function TPingModule.Routes: TRoutes;
begin
Result := [];
end;
end.
The Route Handlers, or route handlers, are responsible for invoking the desired modules based on the routes defined in the AppModule.
unit ping.route.handler;
interface
uses
SysUtils,
result.pair,
dmfbr.modular,
ping.controller,
dmfbr.route.handler;
type
TPingRouteHandler = class(TRouteHandler)
protected
procedure RegisterRoutes; override;
public
function Ping: string;
end;
implementation
uses
dmfbr.route.abstract;
{ TPingRouteHandler }
procedure TPingRouteHandler.RegisterRoutes;
begin
end;
function TPingRouteHandler.Ping: string;
var
LResultPing: string;
LResultRoute: TResultPair<Exception, TRouteAbstract>;
begin
LResultPing := '';
LResultRoute := Modular.LoadRouteModule('/ping');
try
LResultRoute.TryException(
procedure (Error: Exception)
begin
// Failure
LResultPing := Error.Message;
Error.Free;
end,
procedure (Route: TRouteAbstract)
begin
// Success
LResultPing := Modular.Get<TPingController>.Ping;
end);
finally
Modular.DisposeRouteModule('/ping');
end;
Result := LResultPing;
end;
end.
From this point onwards, the choice of the pattern to be adopted is entirely up to you. ModularBr provides complete freedom and flexibility for you to decide which pattern you want to use. In this documentation, we will present an example using the concepts of controller and service, following the principle of single responsibility, in order to illustrate the implementation. However, it is important to note that you have the option to choose other patterns according to your individual needs and preferences.
The Controller
unit ping.controller;
interface
uses
ping.service;
type
TPingController = class
private
FService: TPingService;
public
constructor Create(const AService: TPingService);
destructor Destroy; override;
function Ping: string;
end;
implementation
{ TPingController }
constructor TPingController.Create(const AService: TPingService);
begin
FService := AService;
end;
destructor TPingController.Destroy;
begin
FService.Free;
inherited;
end;
function TPingController.Ping: String;
begin
Result := FService.Ping;
end;
end.
The Service
unit ping.service;
interface
type
TPingService = class
public
function Ping: string;
end;
implementation
{ TPingService }
function TPingService.Ping: string;
begin
Result := 'Pong';
end;
end.