Always return XML content
If you want all methods of a given interface
to return XML
content instead of JSON, you can set
TServiceFactoryServer.ResultAsXMLObject
to true
.
Instead of this JSON array content, returned by default:
GET root/Calculator/Add?n1=1&n2=2 ... {"result":[3]}
or this JSON object, if ServiceFactoryServer.ResultAsJSONObject
is true
:
GET root/Calculator/Add?n1=1&n2=2 ... {"result":{"Result":3}}
The following XML will be returned if
TServiceFactoryServer.ResultAsXMLObject
is true
:
GET root/Calculator/Add?n1=1&n2=2 ...
<?xml version="1.0" encoding="UTF-8"?> <result><Result>3</Result></result>
Conversion is processed from the JSON content generated by the
mORMot kernel, via a call to JSONBufferToXML()
function,
which performs the XML generation without almost no memory allocation. So only
a slightly performance penalty may be noticed (much faster in practice than
most node-based XML producers available).
One drawback of using this
TServiceFactoryServer.ResultAsXMLObject
property is that your
regular Delphi or AJAX clients won't be able to consume the service any more,
since they expect JSON content.
If you want your service to be consumed either by XML and JSON, you would need
two services. You can therefore define a dedicated interface
to
return XML, and then register this interface to return only XML:
type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] /// add two signed 32 bit integers function Add(n1,n2: integer): integer; end; ICalculatorXML = interface(ICalculator) ['{0D682D65-CE0F-441B-B4EC-2AC75E357EFE}'] end; // no additional method, just new name and GUID
TServiceCalculator = class(TInterfacedObject, ICalculator,ICalculatorXML) public // implementation class should implement both interfaces function Add(n1,n2: integer): integer; end;
... aServer.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculator)],sicShared); aServer.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculatorXML)],sicShared). ResultAsXMLObject := True; ...
There would therefore be two running service instances (e.g. here two
instances of TServiceCalculator
, one for ICalculator
and one for ICalculatorXML
). It could be an issue, in some
cases.
And such a dedicated interface may need more testing and code on the server side, since they will be accessible from two URIs:
GET root/Calculator/Add?n1=1&n2=2 ... {"result":{"Result":3}}
and for ICalculatorXML interface
:
GET root/CalculatorXML/Add?n1=1&n2=2 ...
<?xml version="1.0" encoding="UTF-8"?> <result><Result>3</Result></result>
Return XML content on demand
As an alternative, you can let the mORMot server inspect the
incoming HTTP headers, and return the content as XML if the
"Accept:
" header is exactly "application/xml
" or
"text/xml
".
You can set the
TServiceFactoryServer.ResultAsXMLObjectIfAcceptOnlyXML
property to
enable this HTTP header detection:
aServer.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculator)],sicShared).
ResultAsXMLObjectIfAcceptOnlyXML := true;
For standard requests, the incoming HTTP header will be either void, either
"Accept: */*
", so will return JSON content.
But if the client set either "Accept: application/xml
" or
"Accept: text/xml
" in its header, then it will return an XML
document.
Instead of this JSON content:
GET root/Calculator/Add?n1=1&n2=2 Accept: */* ... {"result":{"Result":3}}
The following XML will be returned:
GET root/Calculator/Add?n1=1&n2=2
Accept: application/xml
...
<?xml version="1.0" encoding="UTF-8"?> <result><Result>3</Result></result>
as it would with "text/xml
":
GET root/Calculator/Add?n1=1&n2=2
Accept: text/xml
...
<?xml version="1.0" encoding="UTF-8"?> <result><Result>3</Result></result>
Note that the header is expected to be "Accept:
application/xml
" or "Accept: text/xml
" as exact
value.
For instance "Accept: text/html,application/xml,*/*
" won't be
detected by the server, and will return regular JSON:
GET root/Calculator/Add?n1=1&n2=2 Accept: text/html,application/xml,*/* ... {"result":{"Result":3}}
Your XML client should therefore be able to force the exact content of the
HTTP "Accept:
" header.
Together with parameter values optionally encoded at URI level - available
with TSQLRestRoutingREST
default routing scheme (see
?n1=1&n2=2
above)- it could be an useful alternative to
consume mORMot services from any XML-based client.
Feedback is welcome on our forum, as usual!