MARS-Curiosity and Devart: UniDAC, IBDAC and MyDAC
If you build data-centric applications with Delphi, there is a good chance your data access layer has a name: FireDAC, or one of the Devart data access components. With MARS-Curiosity 2.0 all of them lead to a REST server. Next to FireDAC, MARS now covers the Devart family: UniDAC, supported since 2019, is joined by IBDAC (InterBase and Firebird) and MyDAC (MySQL and MariaDB). The three integrations share the same programming model and the same features, and each one has its client components and a complete demo.
FireDAC got us here
FireDAC has been the main data access layer of MARS for years, and a very good one. A resource method returns a TFDQuery and MARS writes it as JSON; a Delphi client fetches the data into memory tables, lets the user edit it and sends back the changes (the delta) for the server to apply. Connection definitions in the configuration file, parameters filled from the request, several datasets in one response, transactions: everything a data-centric REST server needs, and it has been working in production for a long time.
But FireDAC is not the only data access library Delphi developers trust, and MARS was never meant to depend on one in particular.
A lightweight core and dependency injection
MARS does not bundle a data access library. This was a precise design choice from day one: the core of the library takes care of HTTP, routing, serialization, security and documentation, and leaves the data access to whatever library fits your project and your team.
What connects the two worlds is dependency injection. A resource declares what it needs with the [Context] attribute, and MARS hands it over for the duration of the request:
[Path('customers')]
TCustomersResource = class
protected
[Context] MyDAC: TMARSMyDAC; // or TMARSUniDAC, TMARSIBDAC, TMARSFireDAC
public
[GET, Produces(TMediaType.APPLICATION_JSON)]
function List([QueryParam('city')] const ACity: string): TMyQuery;
end;
Each data access integration is built from the same few pieces:
- an injection service, which creates the connection (or a helper around it) for the request, from a named connection definition of the configuration, and frees it afterwards;
- a helper (
TMARSFireDAC,TMARSUniDAC,TMARSIBDAC,TMARSMyDAC) with queries, commands, stored procedures and transactions, whose parameters named after the request (:QueryParam_city,:PathParam_id) are filled automatically; - readers and writers for the datasets: plain JSON (an array of rows, for any client), XML, and the native format of the library (for Delphi clients);
- client components, to consume the server from Delphi applications.

UniDAC proved the approach back in 2019, when its integration was contributed by ErtanK (thank you!): a second data access library plugged into MARS without touching its core. IBDAC and MyDAC took the same road, and so did the improvements of the last months, which brought the three Devart integrations to the level of the FireDAC one.
And this is the real news for everybody, not only for Devart users: the same path is open to any other library. An ORM, a different DAC, your own data layer: write a custom injection service and your resources receive your session, repository or connection through [Context], exactly as they receive the built-in ones.
Why Devart
Devart is one of the long-standing component vendors of the Delphi ecosystem. Their data access components have been powering data-centric Delphi applications for many years, and they come in two flavors: UniDAC, one set of components with a provider for each database (Oracle, SQL Server, MySQL, PostgreSQL, InterBase, Firebird, SQLite and more), and specialized libraries such as IBDAC for InterBase and Firebird and MyDAC for MySQL and MariaDB (with its direct mode, connecting without a client library).
Many teams have years of code, knowledge and habits built on them. With MARS, whether you use the universal one or the specialized ones, your Devart components can serve your data over REST: to web front-ends, mobile apps, other services, AI agents, and to your existing Delphi clients.
What you get
The Devart integrations follow the FireDAC one feature by feature:
- connection definitions in
Server.ini, by name, loaded once by the server (a UniDAC definition names its provider); - injection of the connection (
TUniConnection,TIBCConnection,TMyConnection) or of the helper, the recommended choice, with[Connection('NAME')]to pick a definition per resource or method; - parameters from the request:
:QueryParam_*,:PathParam_*,:FormParam_*… filled for you, plus macros; - datasets as JSON, XML or native formats (
application/json-unidac,application/json-ibdac,application/json-mydac), chosen by theAcceptheader of the client; several datasets in one response; - transactions (
InTransaction: commit at the end, rollback on exception) and stored procedures (OpenStoredProc,ExecStoredProc); - IBDAC specifics:
RETURNINGclauses, more transactions per connection as InterBase and Firebird allow; - client components:
TMARSUniDACResource,TMARSIBDACResourceandTMARSMyDACResourcefetch the datasets in the native format and send them back; - OpenAPI documentation of the rows (
[MetaResult]), with Swagger UI and Stoplight Elements pages; - demos:
UniDACDemo,IBDACDemoandMyDACDemo, the same customers application as the FireDAC one, server and client.
UniDAC users get some news too: the client components and the new UniDACDemo came with 2.0, its package compiles with Delphi 13, connection definitions accept items with spaces (Provider Name), and transactions roll back on Firebird and InterBase as they should.
Here is what happens when a client asks for the customers of a city:

A taste of the code
The configuration holds the connection definition:
MyDAC.MAIN_DB.Server=localhost
MyDAC.MAIN_DB.Port=3306
MyDAC.MAIN_DB.Database=mars_demo
MyDAC.MAIN_DB.User ID=mars
MyDAC.MAIN_DB.Password=secret
The ignition of the server loads it:
FAvailableConnectionDefs := TMARSMyDAC.LoadConnectionDefs(FEngine.Parameters, 'MyDAC');
And a resource uses it, returning the query: MARS opens it, writes it in the format the client asked for and frees it after the response.
function TCustomersResource.List(const ACity: string): TMyQuery;
begin
if ACity = '' then
Result := MyDAC.Query('select * from customers order by name')
else
Result := MyDAC.Query('select * from customers where city = :QueryParam_city order by name');
end;
A transfer between two customers, all or nothing:
MyDAC.InTransaction(
procedure (ATransaction: TMyTransaction)
begin
if MyDAC.ExecuteSQL('update customers set credit = credit - :QueryParam_amount'
+ ' where id = :QueryParam_from and credit >= :QueryParam_amount', ATransaction) = 0 then
raise EMARSHttpException.Create('Insufficient credit', 409); // rollback
MyDAC.ExecuteSQL('update customers set credit = credit + :QueryParam_amount'
+ ' where id = :QueryParam_to', ATransaction);
end
);
With UniDAC and IBDAC the code is the same, with TMARSUniDAC and TUniQuery, or TMARSIBDAC and TIBCQuery.
Getting started
- Install MARS-Curiosity 2.0 (the latest release is on GitHub): the setup builds the packages of the Devart libraries it finds installed.
- Enable the integration with its define,
MARS_UNIDAC,MARS_IBDACorMARS_MYDAC, inMARS.incor in the options of your project. - Start from the demos (
Demos/UniDACDemo,Demos/IBDACDemo,Demos/MyDACDemo) or from a new project created with MARSCmd.
The documentation has a page for each library and one for the model they share:
- Data Access: the common model;
- UniDAC, IBDAC and MyDAC;
- Devart client components;
- Writing a custom injection service, for any other library.
MARS-Curiosity is open source and free. If you use Devart components and try the integrations, I’d love to hear about it: feedback, issues and ideas are welcome on GitHub.
Your data, your data access library, your REST server. Happy coding!