Last time we looked at how Smart can be used to write a client for a REST server, written in Delphi. This time we’ll see how we could use this approach to work with datasets.
In theory, it should be possible to write a client which works seamlessly with datasets, just like Delphi does when you use a “normal” DataSnap server. In practice, however, even Delphi’s own clients don’t support this with REST servers in versions up to XE6. Only in XE7 a better support for sending FireDAC datasets over REST was added, but this is not yet supported in Smart. So for the time being you will have to do some manual work and write some dataset-wrapping code on the server (and also on the client).
For a demo server we’ll be using the FishFactsIndy application, which is included in all modern Delphis up to XE6. It is missing from the XE7 (it was replaced with the FireDAC JSON Reflection Demo “Customers”), but you can still compile demo from older Delphi if you install BDE (available to registered users only).
This demo exposes access to the well-known FishFacts database by implementing few REST APIs which your client can call. Following methods are implemented (in the FishFactsServerMethods unit).
function GetKeys: TJSONArray; overload; function GetImage(Key: String): TStream; function GetFacts(const AKey: string; out ASpeciesName: string; out ACategory: string; out ACommonName: string; out ALengthIn: Double; out ALengthCm: Double): Boolean; function GetNotes(const AKey: string; out ANotes: string): Boolean;
For example, the GetKeys method returns an array of database primary keys. The code can then use those keys to get additional information from the database.
function TFishFactsServerMethods.GetKeys: TJSONArray; var Container: TJSONArray; begin Container := TJSONArray.Create; GetKeys(Container); Result := Container; end; procedure TFishFactsServerMethods.GetKeys(const Container: TJSONArray); begin DataModule.Table1.Active := True; try DataModule.Table1.First; while not DataModule.Table1.Eof do begin Container.AddElement(TJSONString.Create(DataModule.Table1SpeciesNo.AsString)); DataModule.Table1.Next; end; finally DataModule.Table1.Active := False; end; end;
To set up the test environment, just run the program and click Start.
On the Smart side, we proceed as in the previous installment (link):
- Create new visual application.
- Tools, Import DataSnap connector.
- Enter host name and port of the server.
- Click Import.
DataSnap importer is only available in the Smart Mobile Studio Enterprise edition. To use it, you will also need Delphi Enterprise (or RAD Studio Enterprise), XE or newer, installed on the same computer.
Our program has two edit fields where you can configure address and port of the server. Next, a Get keys button downloads all keys from the server and stores them in the cbxKeys combo box. Each time a combo box is changed, database is queried for the new key and information about the selected fish is displayed in the edit box below the combo box. An image of the fish is also loaded and displayed at the bottom.
The code for the client part is available here.
Let’s take a look at some critical parts of the program. First, the data loading.
When the Get keys button is clicked, TFishFactsServerMethods_Client object is created. It’s GetKeys method is then called. A for loop iterates over all returned keys and stores them in the combo box.
procedure TForm1.btnGetKeysClick(Sender: TObject); begin FFishClient := TFishFactsServerMethods_Client.Create( TDataSnap.CreateConnection(inpServer.Text, StrToInt(inpPort.Text), '')); cbxKeys.Items.Clear; for var s in FFishClient.GetKeys.result do cbxKeys.Add(s); end;
Information on the fish and its image are retrieved in the cbxKeys’ OnChange event. Information is retrieved by calling the GetFacts method. For the image part we could call the GetImage method but then we would have to load returned data into the image control somehow. An easier way to achieve this is to just generate image-fetching URL by calling GetImage_URL and passing that to the image control.
procedure TForm1.cbxKeysChanged(Sender: TObject); begin var key := cbxKeys.Items[cbxKeys.SelectedIndex]; var facts := FFishClient.GetFacts(key); outName.Text := Format('%s [%s], %.1f cm', [facts.ASpeciesName, facts.ACategory, facts.ALengthCm]); outImage.LoadFromURL(FFishClient.GetImage_URL(key)); end;
Bright future ahead
Better and simpler ways of working may appear in one of the following releases now that the Embarcadero is supporting FireDAC reflection in XE7. Stay tuned!