#1 2018-07-26 06:24:19

tomek
Member
Registered: 2017-10-24
Posts: 46

How to pass xml to interface based service

Hi
I'm trying to pass pure xml to interface based service with no success. It only works if xml is enclosed in brackets ["<?xml version="1.0" encoding="UTF-8" ?><notify>...</notify>"], otherwise it throws 406-bad input parameters.

Method is declared as follows:

function TNotifySrv.Test(aXml: UTF8String): UTF8String;

Test ajax request:

POST /notify/NotifySrv.Test HTTP/1.1
Host: xx.xx.xx.xx:8092
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: */*
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Length: 96
Content-Type: text/plain;charset=UTF-8
Origin: null
Connection: keep-alive

<?xml version="1.0" encoding="UTF-8" ?><notify>...</notify>

Regards, Tomek

Offline

#2 2018-07-26 07:00:21

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: How to pass xml to interface based service

XML is not handled as input from interface-based services.
It expects JSON content.
Either with brackets (one item per input argument), or as a JSON object (one field per argument).
See https://synopse.info/files/html/Synopse … #TITLE_448

To handle any kind of input, including a pure XML body, use a method-based service.

Offline

#3 2018-07-26 09:36:48

tomek
Member
Registered: 2017-10-24
Posts: 46

Re: How to pass xml to interface based service

ab wrote:

It expects JSON content.
Either with brackets (one item per input argument), or as a JSON object (one field per argument).

I've tried JSON object, but service received empty input

POST /notify/NotifySrv.Test HTTP/1.1
Host: xx.xx.xx.xx:8092
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: */*
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Length: 75
Content-Type: text/plain;charset=UTF-8
Origin: null
Connection: keep-alive

{"notify": {"event": "TEST", "timestamp": "1532530174.872"}, "alert": null}

Offline

#4 2018-07-26 10:08:33

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: How to pass xml to interface based service

Are you sure the JSON object matches the service input parameters?
Ensure you read https://synopse.info/files/html/Synopse … #TITLE_448

Offline

#5 2018-07-26 10:17:57

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 332

Re: How to pass xml to interface based service

try this:

function TNotifySrv.Test(notify: UTF8String): UTF8String;

rename argument "aXml" to "notify".

Regards.

Esteban


Esteban

Offline

#6 2018-07-26 10:49:21

Chaa
Member
Registered: 2011-03-26
Posts: 244

Re: How to pass xml to interface based service

And try use RawJSON:

function TNotifySrv.Test(notify: RawJSON): UTF8String;

Offline

#7 2018-07-26 11:27:02

tomek
Member
Registered: 2017-10-24
Posts: 46

Re: How to pass xml to interface based service

Ok, now I understand how matching parameters and JSON values works.
But it works only for flat JSON, eg:

{"notify": "event_test", "alert": null}

For nested JSON objects

{"notify": {"event": "TEST", "timestamp": "1532530174.872"}, "alert": null}

it throws 406: "INotifySrv.Test failed on notify:UTF8String [missing or invalid value]"

Is it possible to receive nested JSON objects?

Thx for all answers
Regards, Tomek

Offline

#8 2018-07-26 12:22:33

Chaa
Member
Registered: 2011-03-26
Posts: 244

Re: How to pass xml to interface based service

Offline

#9 2018-07-26 13:47:50

tomek
Member
Registered: 2017-10-24
Posts: 46

Re: How to pass xml to interface based service

Thx! now it works like charm wink
Btw: what is the easiest way to extract fields from simple JSON? (eg "event" from Notify example above)
I'm using TJSONTable, but is seems to "heavy" for this purpose.

Regards, Tomek

Offline

#10 2018-07-26 14:28:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: How to pass xml to interface based service

You can use e.g. a TDocVariant:

function TNotifySrv.Test(const notify, alert: variant): RawJSON;
var e: RawUTF8;
begin
  e := notify.event;  // it works!
end;

Or define a record:

type
  TNotifyRec = packed record
     event: RawUTF8;
     timestamp: double;
  end;
function TNotifySrv.Test(const notify: TNotifyRec; const alert: variant): RawJSON;

// and needed under oldest versions of Delphi or with FPC:
initialization
  TJSONSerializer.RegisterCustomJSONSerializerFromText([
    TypeInfo(TNotifyRec ), 'event:RawUTF8 timestamp:double']);
end.

Or use a TSynPersistent with published properties:

type
  TNotifyObject = class(TSynPersistent)
  ...
  published
     property event: RawUTF8 read fEvent write fEvent;
     property timestamp: double read fTimeSTamp write fTimeSTamp;
  end;
function TNotifySrv.Test(const notify: TNotifyObject; const alert: variant): RawJSON;

Offline

#11 2018-07-27 08:19:28

tomek
Member
Registered: 2017-10-24
Posts: 46

Re: How to pass xml to interface based service

ab wrote:

You can use e.g. a TDocVariant:

function TNotifySrv.Test(const notify, alert: variant): RawJSON;
var e: RawUTF8;
begin
  e := notify.event;  // it works!
end;

It's a kind of magic smile

Thx once more.

Regards, Tomek

Offline

#12 2018-07-27 08:47:20

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to pass xml to interface based service

Variant is a magic, but without compile time checked and code insight. And it is quite slow.

Offline

#13 2018-07-27 22:01:45

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,206
Website

Re: How to pass xml to interface based service

Why slow?
TDocVariant is not so slow in practice, just a few nanoseconds slower than direct access.
For transmitted parameters, you can retrieve it once into a local variable, if you want to use it in a loop for instance.

Offline

#14 2018-07-28 07:02:27

jaclas
Member
Registered: 2014-09-12
Posts: 215

Re: How to pass xml to interface based service

Ok, I read this article http://blog.synopse.info/post/2011/07/0 … te-binding and now I know that mORMot has own late binding, and fast :-)

Offline

Board footer

Powered by FluxBB