Getting Started
It's very easy to get your first XData server and client applications running:
1. Create and run an "empty" server
a. From Delphi IDE, choose File > New > Other;
b. From the dialog that appears, navigate to Delphi Projects > TMS XData;
c. Double click "TMS XData VCL Server" to create the server.
Done: a new project will be created, run it, and your server will be running at the address "http://localhost:2001/tms".
You have several different options for this step:
Using the "XData Server Wizards" is just the more straightforward way to create a new server.
If you don't like wizards, you can simply create a new blank application and drop a couple of design-time components to create your server.
If you don't like design-time components and you want to do it 100% from code, just create the server manually.
2. Add your server-side logic using service operations
a. From Delphi IDE, choose File > New > Other;
b. From the dialog that appears, navigate to Delphi Projects > TMS XData;
c. Double click "TMS XData Service" to create a new service. Use the default settings for now.
Done: Two new units will be created, including two server-side sample methods: Sum and EchoString. Your server is doing something!
Using "XData Service Wizard" is just the more straightforward way to add server-side logic.
If you don't like wizards, you can simply create your service operations manually from code, creating a ServiceContract interface and ServiceImplementation class.
Your server is ready! Let's connect to it now!
3. Send requests to the server from clients
Connecting from Delphi client applications
If you are connecting to server from a Delphi application, accessing your server could not be easier. All you need is to use the TXDataClient object:
uses {...}, MyService, XData.Client;
var
Client: TXDataClient;
MyService: IMyService;
SumResult: Double;
begin
Client := TXDataClient.Create;
Client.Uri := 'http://localhost:2001/tms/xdata';
SumResult := Client.Service<IMyService>.Sum(10, 5);
Client.Free;
end;
And that's it! You invoke XData methods as if they were regular procedures in your client application. The MyInterface unit and IMyService interface were created in the previous step above. You just reuse the same code so that in client you don't have to do anything else but call the interface method.
Of course, there are much more advanced features you can use, so you can learn more about TXDataClient.
Connecting from non-Delphi client applications
To invoke the same Sum operation above without TXDataClient, just perform an HTTP request:
GET /tms/xdata/myservice/sum?a=10&b=5 HTTP/1.1
Host: localhost:2001
And you will get your response in JSON format:
{
"value": 15
}
Of course you can simply go to your web browser and navigate to address "http://localhost:2001/tms/xdata/myservice/sum?a=10&b=5" to test it.
XData server is a standard REST/JSON server. Meaning you can access it from any client application that can simply handle JSON and perform HTTP applications. That means virtually all kinds of applications: desktop, web, mobile, IoT, etc., regardless if those applications were built in C# .NET, Java, PHP, JavaScript, TypeScript, C/C++, Swift, etc.
4. (Optional) Automatically publish your existing Aurelius entities
If you use TMS Aurelius, then TMS XData can automatically create CRUD endpoints for some or all of your Aurelius entities. It's a nice feature that saves you time. Note that this is optional, TMS XData doesn't require you to use TMS Aurelius at all.
How to continue from this
Now you can implement your real server. Of course XData allows you to create complex service operations, not just simple ones like the Sum above.
You can receive and return parameters of many different types: primitive types like integers, doubles, strings, guids, dates; complex types like object and arrays; and several specific supported types like strings, streams, etc..
When using non-Delphi clients, it's interesting to learn how routing and parameter binding works, so you know exactly how to invoke a service operation from a non-Delphi application. It's also important to understand how JSON serialization works (how each Delphi type is represented as JSON) to know how to build the JSON to be sent, and how to interpret the received JSON.
Note
Any XData HTTP server is based on the TMS Sparkle framework. According to the Sparkle documentation, to use the Windows (http.sys) based server, you must first reserve the URL your service will process its requests from. If you have installed TMS Sparkle on your computer, the URL "http://+:2001/tms" is already reserved, so you can create your XData server under that address (all examples in this documentation use the base address "http://server:2001/tms/xdata". If you change your base URL to a different port, or to a URL that doesn't start with "tms", you must reserve that URL otherwise your server might fail to start.
Creating the Server Using the XData Server Wizards
The easiest and more straightforward way to get started with XData is using the wizards.
Choose File > New > Other and then look for the TMS XData category under "Delphi Projects".
There you find several wizards to create a new XData Server Application:
- TMS XData VCL Server: Creates a VCL application that runs an XData server using http.sys
Choose the wizard you want, double-click and the application will be created.
As soon as you execute your application, the server is run. The application generated uses the design-time components. Simply learn about the components to configure them. For example, you can drop a TFDConnection component and set it to the TAureliusConnection.AdaptedConnection property to associate a database connection with the XData server.
You can also create the server manually. The wizard is not mandatory and it is one way to get started quickly.
Creating the Server Using Design-Time Components
If you don't want to use the XData Server Wizard, another way to create a XData Server is by manually dropping the design-time components. If you want the RAD, component dropping approach, this is the way to go.
1. Drop a dispatcher component on the form/data module (for example, TSparkeHttpSysDispatcher).
2. Drop a TXDataDBServer component on the form/data module.
3. Associate the TXDataDBServer component with the dispatcher through the Dispatcher property.
4. Specify the BaseUrl property of the server (for example, http://+:2001/tms/xdata).
5. Set the Active property of the dispatcher component to true.
That's all you need. If you want to have a ready-to-use database connection pool, you can use the following extra steps:
6. Drop a TAureliusConnection component on the form/data module and configure it so that it connects to your database (you will need to drop additional database-access components, e.g. TFDConnection if you want to use FireDac, and then associate it to the TAureliusConnection.AdaptedConnection).
7. Drop a TXDataConnectionPool component on the form/data module and associate it to the TAureliusConnection component through the Connection property.
8. Associate the TXDataServer component to the TXDataConnectionPool component through the Pool property.
Creating the Server Manually
Here we describe the steps to create the XData server manually, from code, without using XData Server Wizard or the design-time components:
1. Create an IDBConnectionFactory interface
The IDBConnectionFactory interface is used to create TMS Aurelius IDBConnection interfaces which will be used by the server to connect to the desired database (in that database Aurelius objects will be persisted). You can read more details on the specific topic here: IDBConnectionFactory interface.
Below we provide a code example that creates an IDBConnectionFactory interface which produces IDBConnection interfaces that connect to an MS SQL Server database, based on an existing TSQLConnection component named SQLConnection1 in a data module TMyConnectionDataModule.
uses
{...}, Aurelius.Drivers.Interfaces, Aurelius.Drivers.Base,
Aurelius.Drivers.dbExpress;
var
ConnectionFactory: IDBConnectionFactory;
begin
ConnectionFactory := TDBConnectionFactory.Create(
function: IDBConnection
var
MyDataModule: TMyConnectionDataModule;
begin
MyDataModule := TMyConnectionDataModule.Create(nil);
Result := TDBExpressConnectionAdapter.Create(MyDataModule.SQLConnection1, MyDataModule);
end
));
// Use the ConnectionFactory interface to create an IDBConnectionPool interface
end;
2. Create an IDBConnectionPool interface
The IDBConnectionPool interface is used by the server to retrieve an IDBConnection interface when it is needed. It holds a list of such interfaces, and if there is none available, it uses the IDBConnectionFactory interface to create a new one. Example:
uses
{...}, Aurelius.Drivers.Interfaces, XData.Aurelius.ConnectionPool;
var
ConnectionPool: IDBConnectionPool;
ConnectionFactory: IDBConnectionFactory;
begin
{...}
ConnectionPool := TDBConnectionPool.Create(
50, // maximum of 50 connections available in the pool
// Define a number that best fits your needs
ConnectionFactory
);
// Use the IDBConnectionPool interface to create the XData server module
end;
3. Create a TXDataServerModule object
The TXDataServerModule is the main class of the XData server. It is a Sparkle server module that is added to the Sparkle server for a specific address. Example:
uses
{...}, XData.Server.Module;
var
XDataModule: TXDataServerModule;
ConnectionPool: IDBConnectionPool;
begin
{...}
XDataModule := TXDataServerModule.Create('http://+:2001/tms/xdata', ConnectionPool);
4. Create a THttpSysServer, add the module to it and start the server
Finally, create a TMS Sparkle THttpSysServer object, add the XData module to it, and start the server. Example:
uses
{...}, Sparkle.HttpSys.Server, XData.Server.Module;
var
XDataModule: TXDataServerModule;
Server: THttpSysServer;
begin
Server := THttpSysServer.Create;
Server.AddModule(XDataModule);
Server.Start;
end;
Later on, do not forget to destroy the Server object instance when the application finishes.
Example 1: In-memory SQLite for testing/development
The following example is a minimum console application that illustrates
how to start an XData server at address
"http://localhost:2001/tms/music" using an in-memory SQLite database.
It uses an unit named AureliusEntities
which is not shown here for
simplification. Such a unit should just contain the Aurelius mapped
classes that will be exposed by the server.
An extra note about this example: Since it is an in-memory database, the
database will be empty every time the server starts. Thus, before the
server starts, the method "UpdateDatabase(Connection)", which is
declared in unit DatabaseUtils
(also not listed here), will be called to
create the required tables and data. Such a thing is a regular TMS
Aurelius procedure and is out of the scope of this example as well. The
purpose of this example is to show how to start an XData server.
program SQLiteConsoleServer;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Aurelius.Drivers.Interfaces,
Aurelius.Drivers.SQLite,
Aurelius.Sql.SQLite,
Aurelius.Schema.SQLite,
Sparkle.HttpSys.Server,
XData.Aurelius.ConnectionPool,
XData.Server.Module,
AureliusEntities,
DatabaseUtils;
procedure StartServer;
var
Server: THttpSysServer;
Connection: IDBConnection;
begin
Server := THttpSysServer.Create;
try
Connection := TSQLiteNativeConnectionAdapter.Create(':memory:');
UpdateDatabase(Connection);
Server.AddModule(TXDataServerModule.Create('http://localhost:2001/tms/music',
TDBConnectionPool.Create(1,
function: IDBConnection
begin
Result := Connection;
end)));
Server.Start;
WriteLn('Server started. Press ENTER to stop.');
ReadLn;
finally
Server.Free;
end;
end;
begin
StartServer;
end.
Example 2: MySQL Server with dbExpress (from Delphi code)
The following example is a minimum console application that illustrates
how to start an XData server at address
"http://localhost:2001/tms/music" using dbExpress to connect to a
MySQL database. It is configured in code. It uses an unit named
AureliusEntities
which is not shown here for simplification. Such a
unit should just contain the Aurelius mapped classes that will be
exposed by the server.
The connection pool is configured to hold up to 25 connections to the database.
program DBExpressConsoleServer;
{$APPTYPE CONSOLE}
uses
System.SysUtils, SqlExpr, DBXMySQL,
Aurelius.Drivers.Base,
Aurelius.Drivers.Interfaces,
Aurelius.Drivers.dbExpress,
Aurelius.Sql.MySQL,
Aurelius.Schema.MySQL,
Sparkle.HttpSys.Server,
XData.Aurelius.ConnectionPool,
XData.Server.Module,
AureliusEntities in '..\common\AureliusEntities.pas';
procedure StartServer;
var
Server: THttpSysServer;
ConnFactory: IDBConnectionFactory;
begin
Server := THttpSysServer.Create;
try
// Example using dbExpress. Create a connection factory to use later
ConnFactory := TDBConnectionFactory.Create(
function: IDBConnection
var
SqlConn: TSQLConnection;
begin
SqlConn := TSQLConnection.Create(nil);
SqlConn.DriverName := 'MySQL';
SqlConn.GetDriverFunc := 'getSQLDriverMySQL';
SqlConn.VendorLib := 'libmysql.dll';
SqlConn.LibraryName := 'dbxmys.dll';
SqlConn.Params.Values['HostName'] := 'dbserver';
SqlConn.Params.Values['Database'] := 'xdata';
SqlConn.Params.Values['User_Name'] := 'user';
SqlConn.Params.Values['Password'] := 'mysql';
SqlConn.LoginPrompt := false;
Result := TDBExpressConnectionAdapter.Create(SqlConn, true);
end
);
Server.AddModule(TXDataServerModule.Create(
'http://localhost:2001/tms/music',
TDBConnectionPool.Create(25, ConnFactory)
));
Server.Start;
WriteLn('Server started. Press ENTER to stop.');
ReadLn;
finally
Server.Free;
end;
end;
begin
StartServer;
end.
Example 3: MS SQL Server with FireDAC (using TDataModule)
The following example illustrates how to start an XData server at
address "http://localhost:2001/tms/music" using FireDac to connect to
any database (in the example, a MS SQL Server database). Compared to
Example 2,
this example uses a TFDConnection dropped onto a TDataModule to configure
the database connection at design-time. It uses an unit named AureliusEntities
which is not shown here for simplification. Such a unit should just
contain the Aurelius mapped classes that will be exposed by the server.
The connection pool is configured to hold up to 15 connections to the
database.
Thus, consider you have a data module with an existing configured database connection using FireDac:
You can use such a configuration and create one instance of that data module when required by the server. You can use the TFDConnection component from it.
program FireDacConsoleServer;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Aurelius.Drivers.Base,
Aurelius.Drivers.Interfaces,
Aurelius.Drivers.FireDac,
Aurelius.Sql.MSSQL,
Aurelius.Schema.MSSQL,
Sparkle.HttpSys.Server,
XData.Aurelius.ConnectionPool,
XData.Server.Module,
AureliusEntities in '..\common\AureliusEntities.pas',
DBDataModuleUnit in 'DBDataModuleUnit.pas' {DBDataModule: TDataModule};
procedure StartServer;
var
Server: THttpSysServer;
begin
Server := THttpSysServer.Create;
try
Server.AddModule(TXDataServerModule.Create('http://localhost:2001/tms/music',
TDBConnectionPool.Create(15, TDBConnectionFactory.Create(
function: IDBConnection
var
DBDataModule: TDBDataModule;
begin
// Example using FireDac and Data Module
DBDataModule := TDBDataModule.Create(nil);
Result := TFireDacConnectionAdapter.Create(DBDataModule.FDConnection1, DBDataModule);
end
))));
Server.Start;
WriteLn('Server started. Press ENTER to stop.');
ReadLn;
finally
Server.Free;
end;
end;
begin
StartServer;
end.