Manipulating a REST Service Header Using OSB 12.2.1

Version 7

    Oracle SOA Suite 12c includes the ability to use REST more easily than before. One of the complexities that this type of service can have is handling the header; unlike SOAP services, header elements must be specified in the transport header as user attributes. This article by Oracle ACE Associate Sandra Flores explains how to expose a proxy REST service in Oracle Service Bus 12.2.1 (OSB) from one SOAP type, created from WSDL and XSD files.


    By Oracle ACE Associate Sandra Floresace-assoc.jpg


    REST services have become highly relevant in both mobile and Web applications, because they help maintain light exchange of information. Oracle SOA Suite 12c includes the ability to use REST more easily than before. One of the complexities that this type of service can have is handling the header; unlike SOAP services, header elements must be specified in the transport header as user attributes.


    This article will explain how to expose a proxy REST service in Oracle Service Bus 12.2.1 (OSB) from one SOAP type, created from WSDL and XSD files, but with an increased complexity factor: The scenario poses a SOAP service that requires the use of customized elements in the SOAP Envelope Header element; when it is exposed as REST, it must have the same characteristic in some way. Because this particular example requires only one Pipeline for both interfaces (SOAP and REST), the header should be supported in both cases and, as far as possible, treated in the same way. I share my solution for this purpose.


    Let's begin with the definition of the WSDL and XSD files of the SOAP service called "Person". It is very important to highlight how the elements involved in the definition for the message header are declared.




    <wsdl:definitions name="Person" targetNamespace=""
    xmlns:tns="" xmlns:inp1=""
    xmlns:xsd="" xmlns:soap=""
    <xsd:import namespace="" schemaLocation="../XSD/PersonSchema.xsd"/>
    <wsdl:message name="insertPersonRequest">
    <wsdl:part name="parameters" element="inp1:insertPersonRequest"/>
    <wsdl:message name="insertPersonResponse">
    <wsdl:part name="parameters" element="inp1:insertPersonResponse"/>
    <wsdl:message name="serviceSOAFault">
    <wsdl:part name="parameters" element="inp1:serviceSOAFault"/>
    <wsdl:message name="requestHeaderMessage">
    <wsdl:part name="requestHeader" element="inp1:requestHeader"/>
    <wsdl:message name="responseHeaderMessage">
    <wsdl:part name="responseHeader" element="inp1:responseHeader"/>
    <wsdl:portType name="PersonPortType">
    <wsdl:operation name="insertPerson">
    <wsdl:input message="tns:insertPersonRequest"/>
    <wsdl:output message="tns:insertPersonResponse"/>
    <wsdl:fault name="fault" message="tns:serviceSOAFault"/>
    <wsdl:binding name="PersonBinding" type="tns:PersonPortType">
    <soap:binding transport=""/>
    <wsdl:operation name="insertPerson">
    <soap:operation style="document" soapAction="insertPerson"/>
    <soap:body use="literal" namespace=""/>
    <soap:header message="tns:requestHeaderMessage" part="requestHeader" use="literal"/>
    <soap:body use="literal" namespace=""/>
    <soap:header message="tns:responseHeaderMessage" part="responseHeader" use="literal"/>
    <wsdl:service name="PersonService">
    <wsdl:port name="PersonPort" binding="tns:PersonBinding">
    <soap:address location="http://localhost:27007/Person"/>




    <xsd:schema elementFormDefault="qualified" targetNamespace=""
    xmlns:tns="" xmlns:xsd="">
    <!-- ========================= Elements ============================== -->
    <!-- Elements to insert a Person registry -->
    <xsd:element name="insertPersonRequest" type="tns:insertPersonRequestType"/>
    <xsd:element name="insertPersonResponse" type="tns:InsertPersonResponseType"/>
    <!-- Elements for Header and Fault -->
    <xsd:element name="requestHeader" type="tns:RequestHeaderType"/>
    <xsd:element name="responseHeader" type="tns:ResponseHeaderType"/>
    <xsd:element name="serviceSOAFault" type="tns:ServiceSOAFaultType"/>
    <!-- ========================== Types ================================== -->
    <!-- Types required to insert a Person-->
    <xsd:complexType name="insertPersonRequestType">
    <xsd:element name="key" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="lastName" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="age" type="xsd:string" minOccurs="0" maxOccurs="1"/>
    <xsd:element name="occupation" type="xsd:string" minOccurs="0" maxOccurs="1"/>
    <xsd:complexType name="InsertPersonResponseType">
    <xsd:element name="idPerson" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="estatus" type="xsd:string" minOccurs="0" maxOccurs="1"/>
    <!-- Types for Header and Fault -->
    <xsd:complexType name="RequestHeaderType">
    <xsd:element name="idSystem" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="token" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="idTransaction" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:complexType name="ResponseHeaderType">
    <xsd:element name="idTransaccion" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:element name="message" type="xsd:string" minOccurs="1" maxOccurs="1"/>
    <xsd:complexType name="ServiceSOAFaultType">
    <xsd:element name="code" type="xsd:string" minOccurs="0" maxOccurs="1"/>
    <xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1"/>
    <xsd:element name="detail" type="xsd:string" minOccurs="0" maxOccurs="1"/>


    The most relevant thing in the WSDL is that messages should have only one part--otherwise, when required to expose the pipeline as REST, the Expose As REST option will not be shown, because such services do not support multipart messages. For example, if we did something like this, it would be wrong:


    <wsdl:message name="insertPersonRequest">
    <wsdl:part name="parameters" element="inp1: insertPersonRequest"/>
    <wsdl:part name="requestHeader" element="inp1:requestHeader"/>


    The next step is to create the proxy service from WSDL and XSD files. In JDev -- once the OSB project, folders structure and both files have been created -- right click on Person.wsdl, Service Bus, Generate Proxy Service.



    This will open the window where we set the name of the SOAP proxy service, select the binding (previously created in the WSDL), and select the Generate Pipeline option. Click Next.




    Select transport and specify the desired Endpoint URI. Click Finish.



    The requested files will be created. I changed the location of the files to the appropriate folders for better visual control.


    Now let's open the file named Person (equivalent to Composite.xml in BPEL), located at the bottom left of the project. Right-click the Pipeline and Expose As REST.



    In the creation window we will set the name of the REST proxy service, in this case PersonRest. Click Next.



    In the resources configuration window, we need to establish the operations specified in the WSDL and link them to a resource and its corresponding path associated with the REST service.


    Double-click on the empty record in the Resources table (it has just a slash '/'). This will open a window to set the path of the resource. In this case, I called it /insert. Click OK.


    Double click on the record of the Operation Bindings table.


    The configuration window will be opened. Here, we choose the resource and the HTTP verb. In this case I chose POST because my fictitious transaction is an insert on the server. In the Request tab, it is automatically mapped XSD element, and we can choose whether the REST service will receive messages in JSON and XML format, among other things.




    Now we must set the response. To do this, click the Response tab and select the format of the payload. Here we can view the example of the message in multiple formats.



    Once we have finished linking operations with resources, we see the full screen as shown below. Click OK.


    After finishing the automatic creation, we’ll see the SOAP and REST proxy interface associated to the Pipeline. Now we need to edit the Pipeline to add a bit of functionality and get the attributes of the header that interest us. Double-click the Pipeline.



    I added an Operational Branch activity and within it a PipelinePair for insertPerson operation. For the Response Stage I used a Replace activity to simulate the mock response in order to test it.



    The Replace activity is:




    I manually wrote the string text of the XML response as expected for the SOAP service, and I used the inLinedXML function to turn it into an XML format.




    Now, we can deploy and check that the service works well in both proxies, SOAP and REST.










    The most interesting part of this article is related to reading the header of the REST service. So let’s get down to the nitty-gritty.


    I've changed the xml response for both header elements (idSystem and token) and concatenated them to the message output to be readily visible in the test, so the expression stays as follows:



    Notice that the values of the REST service header elements are obtained from the inbound variable:




    Deploy and test the service by sending the idSystem and token values in the HTTP Transport Header. This can be done using the OSB test console in the User - Transport Headers section.







    As you can see in the picture, the response shows the values ??that we sent in the header of the HTTP transport.


    As an additional step, I decided to assign the values ??of our user header obtained from inbound to the header variable. With this action we can work with a single structure in the pipeline, without distinction as to whether it has been an invocation via REST or SOAP.


    For this step, I implemented an XQuery transformation that receives the header and inbound variables, makes validations in either case (REST and SOAP), and sets the values in the header variable. The XQuery source code file is:


    xquery version "1.0" encoding "utf-8";
    (:: OracleAnnotationVersion "1.0" ::)
    declare namespace soap="";
    (:: import schema at "../XSD/soap-env.xsd" ::)
    declare namespace ctx="";
    (:: import schema at "../XSD/MessageContext.xsd" ::)
    declare namespace tp="";
    declare namespace http = "";
    declare namespace per="";
    (:: import schema at "../XSD/PersonSchema.xsd" ::)
    declare variable $requestHeader as element() (:: schema-element(soap:Header) ::) external;
    declare variable $inbound as element() (:: schema-element(ctx:endpoint) ::) external;
    declare function local:setRequestHeader($requestHeader as element() (:: schema-element(soap:Header) ::),
    $inbound as element() (:: schema-element(ctx:endpoint) ::)) {
    <soap:Header xmlns:soap="">
    <per:requestHeader xmlns:per="">
    if (exists($inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='idSystem']/@value))
    else if (exists($requestHeader/per:requestHeader/per:idSystem))
    if (exists($inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='token']/@value))
    else if (exists($requestHeader/per:requestHeader/per:token))
    if (exists($inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='idTransaction']/@value))
    else if (exists($requestHeader/per:requestHeader/per:idTransaction))
    local:setRequestHeader($requestHeader, $inbound)


    In the Pipeline flow, I added a Replace activity to replace the header variable with the output of the XQuery. The Pipeline is as follows:




    Replace activity properties are the following:





    Finally, I changed the Replace activity expression to take a header value of REST and another one of SOAP, just to illustrate that once the transformation has passed, it is feasible to use the header structure.


    The new expression is:


    fn-bea:inlinedXML(fn:concat('<insertPersonResponse xmlns="">
    <idPerson>', $inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name='idSystem']/@value, '</idPerson>
    <estatus>', $header/per:requestHeader/per:token/text(), '</estatus>


    An error will likely be shown when editing the XQuery function, because the namespace prefix called "per" is not declared. If this happens, you only need to add it in the namespaces tab.


    To validate the result, deploy and test the proxy REST, sending token and idSystem headers.


    As shown in the picture, we get the value of the headers, whether from a REST or SOAP request type; these are combined in the header variable and thereafter it is possible to use them as if they had been sent by a SOAP request.


    With this we end the example. I hope you find it helpful for your implementations.



    About the Author

    Oracle ACE Associate Sandra Flores is a SOA architect at S&P Solutions, based in Mexico, where her focus is on services and process solutions.


    This article represents the expertise, findings, and opinion of the author.  It has been published by Oracle in this space as part of a larger effort to encourage the exchange of such information within this Community, and to promote evaluation and commentary by peers. This article has not been reviewed by the relevant Oracle product team for compliance with Oracle's standards and practices, and its publication should not be interpreted as an endorsement by Oracle of the statements expressed therein.