I’m always happy to get input from users of kbmMW about features they would like kbmMW to support.

A short while ago, a user sent an email, stating that he was being asked to provide XML-RPC and possibly JSON-RPC support for some of his clients.

XML-RPC is a fairly old standard made by an employee at Microsoft back in late 80’s. I have not spent much time actually considering supporting it until now, because I have assumed it to be practically out of use, beaten mostly by REST these days.

However digging into it a bit, I find many scenarios where XML-RPC is being used, so of course kbmMW should support it 🙂

XML-RPC is fairly easy to implement as it supports only a very few well defined datatypes and that it is using positional arguments, which makes it integrate nicely with kbmMW’s own RPC style.

One datatype XML-RPC supports which, at least in the old days before kbmMW v5, did not really play well with kbmMW, is a key/value style datatype. However v5 comes to the rescue, since it is way more clever regarding what can be used as arguments and results. Now not only simple types can be handled but just about any type, including the nifty Object Notation ones, including TkbmMWONArray, TkbmMWONObject and TkbmMWONNative. In this case XML-RPC will forward the key/value data as a TkbmMWONObject instance.

Similarly one can return TkbmMWONObject instances from the methods called and it will be understood correctly as a key/value response datatype.

Another Remote Procedure Call method is called JSON-RPC. As the name implies, JSON-RPC use JSON instead of XML as the container format. That also means that anything that can be expressed as JSON can be used as arguments or results in JSON-RPC. Fortunately again the kbmMW Object Notation framework fits in nicely.

Let us define an XML-RPC server.

It is as easy as adding a TCP based server request/response transport like TkbmMWTCPIPIndyServerTransport, and setting its StreamFormat property to XMLRPC and include kbmMWXMLRPCTransStream in the main units uses clause.

Now the server will accept requests like this:

POST http://127.0.0.1/smartdemo

<methodCall>
   <methodName>addnumbers</methodName>
      <params>
         <param>
            <value><i4>11</i4></value>
         </param>
         <param>
            <value><i4>2</i4></value>
         </param>
      </params>
</methodCall>

which will result in responses like this:

<methodResponse>
    <params>
        <param>
            <value>
                <double>13</double>
            </value>
        </param>
    </params>
</methodResponse>

Remember that the request must be given with the mimetype/Content-type text/xml to be valid.

kbmMW supports both UTF-16 and UTF-8 charset setting.

The last part of the URL (after the last /) must be the name of the service optionally with a dot (.) and the version of the service.

Hence SmartService.1.0 is valid as a way to call the service named SmartService version 1.0

If the dot is omitted, the default version will be used, as is normal for kbmMW

If you instead set StreamFormat property to JSONRPC and include kbmMWJSONRPCTransStream in the main unit uses clause, you will have asked kbmMW to understand JSON-RPC v2.0. kbmMW is almost 100% compatible with JSON-RPC except that it currently will not accept batch statements (multiple calls grouped in a JSON array).

Let us look at the same request in JSON-RPC format.

POST http://127.0.0.1/smartdemo

{"jsonrpc": "2.0", "method": "addnumbers", "params": [42, 23], "id": 1}

Which will result in this response

{"jsonrpc":"2.0","id":1,"result":65}

JSON-RPC supports named arguments where the arguments would be provided as a JSON object (key/value list) instead as an array of values. kbmMW will forward this as a TkbmMWONObject to the method being called. So in this case the method must be defined to only receive one argument.

Eg.

POST http://127.0.0.1/smartdemo

{"jsonrpc": "2.0", "method": "addnumbers", "params": {"val1":42, "val2":23}, "id": 1}

The method will have to work like this to get access to the named arguments:

function TMyService.AddNumbers(const Arg:variant):integer;
var
   co:TkbmMWONCustomObject;
   o:TkbmMWONObject;
begin
  if TkbmMWRTTI.GetkbmMWONCustomObject(Arg,co) then
  begin
    if co.IsObject then
    begin
        o:=TkbmMWONObject(co);
        i1:=o.AsInt32['val1'];
        i2:=o.AsInt32['val2'];
...
    end;
 end;
end;

The class TkbmMWRTTI contains a couple of other nice methods that makes it easy to extract other complex values from the variant arguments:

function TkbmMWRTTI.GetkbmMWDateTime(AVariant:variant; var ADateTime:TkbmMWDateTime):boolean

and

function TkbmMWRTTI.GetkbmMWNullable(AVariant:variant; var AIsNull:boolean; var AVariant:variant):boolean

The later will return the value of a kbmMWNullable contained in a variant, and if the value is actually null.

You can return a complex value like this:

Result:=Use.AsResult(akbmMWOnObject);

kbmMW will take care of freeing the object when it is no longer needed.

All this will be available in the upcoming kbmMW release.

You can read more about XML-RPC here: https://www.tutorialspoint.com/xml-rpc/index.htm

and JSON-RPC here: https://www.jsonrpc.org/specification

If you like what you see, please share the word. Reshare blog posts and let others know about the product!

Essentially help us to help you 🙂

Oh… and that feature image…. Why silo’s?

Well the silo is not the important part… the bridge between them is. Without the ability to build bridges between virtual silo’s your application might end up having a hard time in the future.

Loading

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.