Tutorial: Implementing a FireDAC RAD Server Resource
Go Up to RAD Server Resource Overview
You can use an RAD Server package to expand the server in order to expose resources from a database using FireDAC. After expanding the server you can use the RAD Server Console to see analytics of the endpoint calls.
To create your own FireDAC API extending the RAD Server Engine you need to create a RAD Server Package with the resources.
Overview and Architecture
This sample creates a Delphi RAD Server package to expose data from an InterBase database using FireDAC.
To create the new resource:
- Go to File > New > Other > New Items.
- Create a new RAD Server package:
- For Delphi: Delphi Projects > EMS > EMS Package.
- For C++: C++Builder Projects > EMS > EMS Package.
- Select Create package with resource and click Next.
- Enter a resource name, for example "FireDACTest".
- Select Data Module and click Next.
- Select Get and Post and click Finish.
On the Unit1.dfm add the following components:
- A TFDConnection component to connect to the database.
- Right-click to open the Connection Editor.
- Set the Driver ID to IB.
- Set the Database to
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Data\EMPLOYEE.GDB
. - Set the User_Name and Password to sysdba / masterkey if you are using the parameters by default.
- A TFDPhysIBDriverLink component.
- A TFDGUIxWaitCursor component.
- A TFDStanStorageJSONLink component.
- A TFDSchemaAdapter component.
- Two TFDQuery components.
- Rename one TFDQuery to QEmployee and the other one to QCustomer.
- Select the TFDConnection for the Connection property.
- For the SchemaAdapter property select the TFDSchemaAdapter from the drop-down combo-box.
- Right-click to open the Query Editor....
- Enter the SQL command:
- In the QEmployee component: Select * from employee.
- In the QCustomer component: Select * from customer.
- Set the CachedUpdates property to
True
.
- Two TDataSource components.
- Rename one TDataSource to DEmployee and the other one to DCustomer.
- On the DataSet property select the corresponding query.
Write the following code in the Code tab:
- For Delphi:
published
[EndpointName('GetRecords')] // Name of the call to show in the analytics.
procedure Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
[EndpointName('PostUpdates')] // Name of the call to show in the analytics.
procedure Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
- For C++ (in the Unit1.cpp file):
void __fastcall PACKAGE Register()
{
std::auto_ptr<TEMSResourceAttributes> attributes(new TEMSResourceAttributes());
attributes->ResourceName = "FireDACTest";
attributes->EndPointName["Get"] = "GetRecords";
attributes->EndPointName["Post"] = "PostUpdates";
RegisterResource(__typeinfo(TFireDACTestResource1), attributes.release());
}
Write code for the Get procedure.
- For Delphi:
procedure TFireDACTestResource1.Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
oStr: TMemoryStream;
begin
oStr := TMemoryStream.Create;
try
QEmployee.Open;
QCustomer.Open;
FDSchemaAdapter1.SaveToStream(oStr, TFDStorageFormat.sfJSON);
// Response owns stream
AResponse.Body.SetStream(oStr, 'application/vnd.embarcadero.firedac+json', True);
except
oStr.Free;
raise;
end;
end;
- For C++ (in the Unit1.cpp file):
void TFireDACTestResource1::Get(TEndpointContext* AContext, TEndpointRequest* ARequest, TEndpointResponse* AResponse) {
std::auto_ptr<TMemoryStream> oStr(new TMemoryStream());
QEmployee->Open();
QCustomer->Open();
FDSchemaAdapter1->SaveToStream(oStr.get(), TFDStorageFormat::sfJSON);
AResponse->Body->SetStream(oStr.release(), "application/vnd.embarcadero.firedac+json", true);
}
Write code for the Post procedure.
- For Delphi:
procedure TFireDACTestResource1.Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
LStream: TStream;
begin
if not SameText(ARequest.Body.ContentType, 'application/vnd.embarcadero.firedac+json') then
AResponse.RaiseBadRequest('content type');
if not ARequest.Body.TryGetStream(LStream) then
AResponse.RaiseBadRequest('no stream');
LStream.Position := 0;
FDSchemaAdapter1.LoadFromStream(LStream, TFDStorageFormat.sfJSON);
FDSchemaAdapter1.ApplyUpdates
end;
- For C++ (in the Unit1.cpp file):
void TFireDACTestResource1::Post(TEndpointContext* AContext, TEndpointRequest* ARequest, TEndpointResponse* AResponse) {
TStream* LStream;
if (!(SameText(ARequest->Body->ContentType, "application/vnd.embarcadero.firedac+json")))
AResponse->RaiseBadRequest("content type");
if (!(ARequest->Body->TryGetStream(LStream)))
AResponse->RaiseBadRequest("no stream");
LStream->Position = 0;
FDSchemaAdapter1->LoadFromStream(LStream, TFDStorageFormat::sfJSON);
FDSchemaAdapter1->ApplyUpdates();
}
- Only for C++: Add the following component's package and its dependencies to the Requires node:
- In the Projects Window, right-click the Requires node.
- Select Add Reference ... .
- Set the Search path field to:
C:\Program Files (x86)\Embarcadero\Studio\21.0\lib\win32\release
- Add the following packages in the Package name field:
FireDACCommonDriver.bpi FireDACCommon.bpi FireDAC.bpi FireDACIBDriver.bpi
Testing the New Resource
To test your project on a developer environment:
- Go to Run > Parameters.
- Check the Host application field to see if the path to the RAD Server Engine executable is correct. The path is
C:\Program Files (x86)\Embarcadero\Studio\21.0\bin\EMSDevServer.exe
. - Go to Run > Run Without Debugging to run the project.
- The Server window opens. Click Open Browser to open the server in your regular browser.
- Note: A window appears to make some necessary changes to your project. Click OK.
If this is the first time you run the server you need to follow the steps in Running a Developer Environment to create the IB file and the configuration file.
Enter the following URL in a browser:
http://localhost:8080/FireDACTest/ //It shows the defined queries as JSON data.
The result should look like this:
{"FDBS":{"Version":14,"Manager":{"UpdatesRegistry":true,"TableList":[{"class":"Table","Name":"QEmployee","SourceName":"employee","SourceID":1,"TabID":0,"EnforceConstraints":false,"MinimumCapacity":50,"ColumnList":[{"class":"Column","Name":"EMP_NO","SourceName":"EMP_NO","SourceID":1,"DataType":"Int16","Searchable":true,"Base":true,"OInUpdate":true,"OInWhere":true,"OInKey":true,"OriginTabName":"EMPLOYEE","OriginColName":"EMP_NO"},{"class":"Column","Name":"FIRST_NAME","SourceName":"FIRST_NAME","SourceID":2,"DataType":"AnsiString","Size":15,"Searchable":true,"Base":true,"OInUpdate":true,"OInWhere":true,"OriginTabName":"EMPLOYEE","OriginColName":"FIRST_NAME","SourceSize":15},{"class":"Column","Name":"LAST_NAME","SourceName":"LAST_NAME","SourceID":3,"DataType":"AnsiString","Size":20,"Searchable":true,"Base":true,"OInUpdate":true,"OInWhere":true,"OriginTabName":"EMPLOYEE","OriginColName":"LAST_NAME","SourceSize":20},{"class":"Column","Name":"PHONE_EXT","SourceName":"PHONE_EXT","SourceID":4,"DataType":"AnsiString","Size":4,"Searchable":true,"AllowNull":true,"Base":true,"OAllowNull":true,"OInUpdate":true,"OInWhere":true,"OriginTabName":"EMPLOYEE","OriginColName":"PHONE_EXT","SourceSize":4},{"class":"Column","Name":"HIRE_DATE","SourceName":"HIRE_DATE","SourceID":5,"DataType":"DateTimeStamp","Searchable":true,"Base":true,"OInUpdate":true,"OInWhere":true,"OriginTabName":"EMPLOYEE","OriginColName":"HIRE_DATE"},
...
You can also see the calls to the 'GetRecords' endpoint on the console. See Setting Up Your RAD Server Console for more information.