Define an interface

The current implementation of service has the following expectations:
- Any interface inheriting from IInvokable, with a GUID, can be used - we expect the RTTI to be available, so IInvokable is a good parent type;
- You can inherit an interface from an existing one: in this case, the inherited methods will be part of the child interface, and will be expected to be implemented (just as with standard Delphi code);
- Only plain ASCII names are allowed for the type definition (as it is conventional to use English spelling for service and operation naming);
- Calling convention shall be register (the Delphi's default) - nor stdcall nor cdecl is available yet, but this won't be a restriction since the interface definition is dedicated to Delphi code scope;
- Methods can have a result, and accept per-value or per-reference parameters.

In fact, parameters expectations are the following:
- Simple types (strings, numbers, dates, sets and enumerations) and high-level types (objects, collections, records and dynamic arrays) are handled - see below for the details;
- They can be defined as const, var or out - in fact, const and var parameters values will be sent from the client to the server as JSON, and var and out parameters values will be returned as JSON from the server;
- procedure or function kind of method definition are allowed;
- Only exception is that you can't have a function returning a class instance (how will know when to release the instance in this case?), but such instances can be passed as const, var or out parameters (and published properties will be serialized within the JSON message).

Available types for methods

Handled types of parameters are:

Delphi type Remarks
boolean Transmitted as JSON true/false
integer cardinal Int64 double currency TDateTime Transmitted as JSON numbers
enumerations Transmitted as JSON number
set Transmitted as JSON number - one bit per element (up to 32 elements)
RawUTF8 WideString Transmitted as JSON text (UTF-8 encoded)
string Transmitted as UTF-8 JSON text, but prior to Delphi 2009, the framework will ensure that both client and server sides use the same ANSI code page - so you should better use RawUTF8
TPersistent Published properties will be transmitted as JSON object
TSQLRecord All fields (including ID) will be transmitted as JSON object
dynamic arrays Transmitted as JSON arrays
record Transmitted as binary with Base-64 encoding, needed to have RTTI (so a string or dynamic array field within), just like with regular Delphi interface expectations

You can therefore define complex interface types, as such:

type
  ICalculator = interface(IInvokable)
    ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
    /// add two signed 32 bit integers
    function Add(n1,n2: integer): integer;
    /// multiply two signed 64 bit integers
    function Multiply(n1,n2: Int64): Int64;
    /// substract two floating-point values
    function Subtract(n1,n2: double): double;
    /// convert a currency value into text
    procedure ToText(Value: Currency; var Result: RawUTF8);
    /// convert a floating-point value into text
    function ToTextFunc(Value: double): string;
    /// do some work with strings, sets and enumerates parameters,
    // testing also var (in/out) parameters and set as a function result
    function SpecialCall(Txt: RawUTF8; var Int: integer; var Card: cardinal; field: TSynTableFieldTypes;
      fields: TSynTableFieldTypes; var options: TSynTableFieldOptions): TSynTableFieldTypes;
    /// test integer, strings and wide strings dynamic arrays, together with records
    function ComplexCall(const Ints: TIntegerDynArray; Strs1: TRawUTF8DynArray;
      var Str2: TWideStringDynArray; const Rec1: TVirtualTableModuleProperties;
      var Rec2: TSQLRestCacheEntryValue): TSQLRestCacheEntryValue;
  end;

Note how SpecialCall and ComplexCall methods have quite complex parameters definitions, including dynamic arrays, sets and records.

The framework will handle const and var parameters as expected, i.e. as input/output parameters, also on the client side. And simple types of dynamic arrays (like TIntegerDynArray, TRawUTF8DynArray, or TWideStringDynArray) will be serialized as plain JSON arrays - the framework is able to handle any dynamic array definition, but will serialize those simple types in a more AJAX compatible way.

Continue reading...

This article is part of a list of other blog articles, extracted from the official Synopse mORMot framework documentation:

Feedback and questions are welcome on our forum, just as usual.