Defining Custom Processing in a Web Service
In rare scenarios, it may be useful to define an InterSystems IRIS® data platform web service that uses custom processing to handle inbound messages and to build response messages. In these scenarios, you implement either the ProcessBodyNode() method or the ProcessBody() method in the web service. This topic provides the details.
Overview
In custom processing, you parse the inbound message and construct the response manually. The requirements are as follows:
-
In the web service, you define web methods that have the desired signatures. You do this to establish the WSDL of the web service. These web methods (or some of them) can be stubs. A method is executed only if ProcessBodyNode() or ProcessBody() returns 0.
-
Also in the web service, you implement one of the following methods:
-
ProcessBodyNode() — This method receives the SOAP body as an instance of %XML.NodeOpens in a new tab. You can use InterSystems IRIS XML tools to work with this instance and build the response message. The SOAP envelope is available in the Document property of this instance of %XML.NodeOpens in a new tab.
-
ProcessBody() — This method receives the SOAP Body as a stream. Because the SOAP body is an XML fragment rather than an XML document, you cannot use the InterSystems IRIS XML tools to read it. Instead, you parse the stream with ObjectScript functions and extract the needed parts.
If you define both of these methods, the ProcessBodyNode() method is ignored.
-
In either case, the response message that you construct must be consistent with the WSDL of the web service.
Implementing ProcessBodyNode()
The ProcessBodyNode() method has the following signature:
method ProcessBodyNode(action As %String, body As %XML.Node,
ByRef responseBody As %CharacterStream) as %Boolean
Where:
-
action is the SOAP action specified in the inbound message.
-
body is an instance of %XML.NodeOpens in a new tab that contains the SOAP <Body>.
-
responseBody is the response body serialized as an instance of %Library.CharacterStreamOpens in a new tab. This stream is passed by reference and is initially empty.
If you implement this method in a web service, the method should do the following:
-
Examine the action and branch accordingly. For example:
if action["action1" { //details }
-
If you need to access the SOAP <Envelope> (for example, to access its namespace declarations), use the Document property of body. This equals an instance of %XML.DocumentOpens in a new tab, which represents the SOAP envelope as a DOM (Document Object Model).
Otherwise, use body directly.
-
Now you have the following options:
-
Use %XML.WriterOpens in a new tab to write the body as a string, which you can then manipulate. For example:
set writer=##class(%XML.Writer).%New() do writer.OutputToString() do writer.DocumentNode(body) set request=writer.GetXMLString(.sc) // check returned status and continue
-
Use methods of %XML.DocumentOpens in a new tab or %XML.NodeOpens in a new tab, as appropriate, to navigate through the document. Similarly, use properties of %XML.DocumentOpens in a new tab or %XML.NodeOpens in a new tab to access information about the current part of the document.
-
Use XPath expressions to extract data.
-
Perform XSLT transformations.
For details, see Using XML Tools. Be sure to check the status returned by methods in these classes, to simplify troubleshooting in the case of an error.
-
-
If an error occurs during the processing of the request, return a fault in the usual way using the ReturnFault() method.
-
Use the Write() method of the response stream to write the XML fragment which will become the child element of <Body>.
-
If a response stream is created, return 1. Otherwise, return 0, which causes InterSystems IRIS to run the web method associated with the given action.
For example:
if action["action1" { //no custom processing for this branch quit 0 } elseif action["action2" { //details //quit 1 }
Implementing ProcessBody()
The ProcessBody() method has the following signature:
method ProcessBody(action As %String, requestBody As %CharacterStream,
ByRef responseBody As %CharacterStream) as %Boolean
Where:
-
action is the SOAP action specified in the inbound message.
-
requestBody is an instance of %Library.CharacterStreamOpens in a new tab that contains the SOAP <Body> element. The stream contains an XML fragment, not a complete XML document.
-
responseBody, is the response body serialized as an instance of %Library.CharacterStreamOpens in a new tab. This stream is passed by reference and is initially empty.
If you implement this method in a web service, the method should do the following:
-
Examine the action and branch accordingly. For example:
if action["action1" { //details }
-
Use the Read() method of requestBody to obtain the SOAP <Body>. For example:
set request=requestBody.Read()
-
Parse this stream by using tools such as $EXTRACT. For example:
set in1="<echoString xmlns=""http://soapinterop.org/xsd""><inputString>" set in2="</inputString></echoString>" set contents=$extract(request,$length(in1)+1,*-$length(in2))
-
If an error occurs during the processing of the request, return a fault in the usual way using the ReturnFault() method.
-
Use the Write() method of the response stream to write the XML fragment that will become the child element of <Body>. For example:
set in1="<echoString xmlns=""http://soapinterop.org/xsd""><inputString>" set in2="</inputString></echoString>" set request=requestBody.Read() if ($extract(request,1,$length(in1))'=in1) || ($extract(request,*-$length(in2)+1,*)'=in2) { do responseBody.Write("Bad Request: "_request) quit 1 } set out1="<echoStringResponse xmlns=""http://soapinterop.org/xsd""><echoStringResult>" set out2="</echoStringResult></echoStringResponse>" do responseBody.Write(out1) do responseBody.Write($extract(request,$length(in1)+1,*-$length(in2))) do responseBody.Write(out2)
-
If a response stream is created, return 1. Otherwise, return 0, which causes InterSystems IRIS to run the web method associated with the given action.