We'll implement the same example as in the official Embarcadero docwiki page above. Add two numbers. Very useful service, isn't it? wink

Server side

We'll first code the Server-side:

First the declaration of the class:

TSQLRestServerTest = class(TSQLRestServerDB)
  published
    function Sum(aRecord: TSQLRecord; aParameters: PUTF8Char;
      const aSentData: RawUTF8; out aResp, aHead: RawUTF8): Integer;
  end;

This method name will be used for the URL encoding, and will be called here with ModelRoot/Sum URL. The ModelRoot is the one defined in the Root parameter of the model used by the application.

This method, like all Server-side methods, MUST have all parameters of the TSQLRestServerCallBack prototype:

type
  TSQLRestServerCallBack = function(aRecord: TSQLRecord;
      aParameters: PUTF8Char; const aSentData: RawUTF8;
      out aResp, aHead: RawUTF8): Integer of object;

Then we implement this method:

function TSQLRestServerTest.Sum(aRecord: TSQLRecord; aParameters: PUTF8Char;
  const aSentData: RawUTF8; out aResp, aHead: RawUTF8): Integer;
var a,b: Extended;
begin
  if not UrlDecodeNeedParameters(aParameters,'A,B') then
  begin
    result := 404; // invalid Request
    exit;
  end;
  while aParameters<>nil do
  begin
    UrlDecodeExtended(aParameters,'A=',a);
    UrlDecodeExtended(aParameters,'B=',b,@aParameters);
  end;
  aResp := JSONEncodeResult([a+b]);
  // same as : aResp := JSONEncode(['result',a+b],TempMemoryStream);
  result := 200; // success
end;

Not difficult to follow, isn't?

On the Server side, you can use the UrlDecodeNeedParameters function to check that an expected parameters were supplied by the caller, then call UrlDecodeInteger / UrlDecodeInt64 / UrlDecodeExtended / UrlDecodeValue functions (all defined in SynCommons.pas) to retrieve each individual parameter as standard JSON content. The powerful UrlDecodeObject function (defined in SQLite3Commons.pas) can be used to unserialize most class instance from its textual JSON representation.

The Client is always right

OK, now the client-side:

function Sum(aClient: TSQLRestClientURI; a, b: double): double;
var err: integer;
begin
  val(aClient.CallBackGetResult('sum',['a',a,'b',b]),Result,err);
end;

And... that's all!

You could even implement this method in a dedicated client method:

type
  TMyClient = class(TSQLite3HttpClient) // could be TSQLRestClientURINamedPipe
  (...)
    function Sum(aClient: TSQLRestClientURI; a, b: double): double;
  (...)
function TMyClient.Sum(a, b: double): double;
var err: integer;
begin
  val(CallBackGetResult('sum',['a',a,'b',b]),Result,err);
end;

This later implementation is to be preferred on real applications.

You have to create the server instance, and the corresponding TSQLRestClientURI (or TMyClient), with the same database model, just as usual...

On the Client side, you can use the CallBackGetResult method to call the service from its name and its expected parameters, or create your own caller using the UrlEncode() function. Note that you can specify most class instance into its JSON representation by using some TObject into the parameter lists:

function TMyClient.SumMyObject(aClient: TSQLRestClientURI; a, b: TMyObject): double;
var err: integer;
begin
  val(aClient.CallBackGetResult('summyobject',['a',a,'b',b]),Result,err);
end;

Whatever you need

Note that this Client-Server protocol uses JSON here, but you can serve any kind of data, binary, HTML, whatever...

The usual protocols of our framework can be used: HTTP/1.1, Named Pipe, Windows GDI messages, direct in-memory/in-process access.

Just to be noticed that the data transmitted is a valid JSON content, like this one:

{ "result":3.141592653 }

So you can consume these services, implemented Server-Side in fast Delphi code, with any AJAX application Client-Side.

Of course, these services can be related to any table/class of our ORM framework, so you would be able to create easily any RESTful compatible requests on URL like ModelRoot/TableName/ID/MethodName. For example, here we return a BLOB field content as hexadecimal:

function TSQLRestServerTest.DataAsHex(aRecord: TSQLRecordPeople; aParameters: PUTF8Char;
  const aSentData: RawUTF8; var aResp, aHead: RawUTF8): Integer;
var aData: TSQLRawBlob;
begin
  result := 404; // invalid Request
  if (self=nil) or (aRecord=nil) or not aRecord.InheritsFrom(TSQLRecord) or
    (aRecord.ID<0) then
    exit; // we need a valid record and its ID
  if not RetrieveBlob(TSQLRecordPeople,aRecord.ID,'Data',aData) then
    exit; // impossible to retrieve the Data BLOB field
  aResp := JSONEncodeResult([SynCommons.BinToHex(aData)]);
  // idem: aResp := JSONEncode(['result',BinToHex(aRecord.fData)],TempMemoryStream);
  result := 200; // success
end;

Full source code is available in our Source Code Repository.
It should work from Delphi 6 to Delphi XE.

Article update:
The server side call back signature changed since this article was published.
Please refer to the documentation or this blog article.