IBM Support

SBI SOAP Series Part 2: Limiting a Web Service Response for the Client

Technical Blog Post


Abstract

SBI SOAP Series Part 2: Limiting a Web Service Response for the Client

Body

In my previous blog post, we took a look at setting up a basic Web Service Provider on Sterling B2B Integrator (SBI). We successfully received a response in our SOAP client, but SBI was returning all of Process Data, rather than just the nodes that the client needs. This post will walk us through implementing the schemas and BP mappings that will limit the nodes that are included in the SOAP response.

The first thing we should do is come up with schemas that define the format of the input received from the client, and the output we want to provide to the client. These schemas can be used not only to define the structure of the request from the partner, but also can be used to validate and enforce the structure of the inbound request. Creation of the schemas really has nothing to do with SBI, so use your favorite XML tool for this task. I use Altova XMLSpy.

As we said in the last post, our test service is taking a customer ID and converting that to a customer name. Going forward, we will also eventually be adding some namespaces to our request and response to ensure that collisions will not occur if the SOAP client is working with other XML nodes with identical names. Let's create some suitable schemas.

The following input schema defines an input value for the customerId node as an 8 digit alpha-numeric character only:

<?xml version="1.0" encoding="UTF-8"?>
<xs:element name="customerId">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[a-zA-Z0-9]{8}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="BSWS_NameLookup">
<xs:complexType>
<xs:sequence>
<xs:element ref="customerId"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Here's the output schema, that is just defining string output for our return values:

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

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.sterlingcommerce.com/ibmws_out">
<xs:element name="NameData">
<xs:complexType>
<xs:choice maxOccurs="3">
<xs:element name="LastName" type="xs:string"/>
<xs:element name="FirstName" type="xs:string"/>
<xs:element name="Prefix" type="xs:string"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>

Check these in under Deployment → Schemas. Here's a screenshot of my schemas after being checked in. You can see that I chose targetNamespaces that include an _in or _out, when checking them in to avoid targetNamespace collision in SBI.

image

The next step is to add the BP Schema mapping so that the web service knows which schemas to use. They are assigned to the business process that will be processing the input SOAP request and generating the SOAP response. In our case, that is BSWS_ProvideName. This is the BP that gets inline invoked during the SOA_MessageHandler and SOA_RequestHandler business processes.

For now, I'm leaving validation turned off, just so we can see the affect of enabling the schema mapping. Here's what the BP Schema mapping looks like after creation (Deployment → Web Services → Schema Mappings):

image

Now, let's also modify the BP so that we can limit the response. The key to this is to have a valid XML node structure placed under a node called WebservicesResponseNode in Process Data. When the schemas above are mapped to the BP, it will use those nodes as the response and that is what is passed through the schema for validation. Here's the modified BP:

<process name="BSWS_NameLookup">
<sequence>
<operation name="AssignService">
<participant name="AssignService"/>
<output message="AssignOutputMessage">
<assign to="." from="*"/>
<assign to="WebservicesResponseNode/NameData/Prefix">Mr.</assign>
<assign to="WebservicesResponseNode/NameData/FirstName">Brian</assign>
<assign to="WebservicesResponseNode/NameData/LastName">Sak</assign>
</output>
<input message="AssignInputMessage">
<assign to="." from="*"/>
</input>
</operation>
</sequence>
</process>

So, let's see where we are with regards to results. We will generate a new WSDL for our web service and see what changes have occurred. Go to Deployment → Web Services → Manager and then Generate WSDL and View WSDL.

Now, you should see the schemas that we checked in as part of the web service definition itself inside of the WSDL. You can also see that the namespace values were changed so they match the targetNamespace that was entered when you checked the schemas in. This would keep collisions from occurring in the event that the request and response had some nodes sharing a name, but with different restrictions on those elements in their respective schemas.

If you check this WSDL in to the soapUI, generate a new request and post it, your results should look like this:

image

You can see that we only receive the details that we want rather than the entire set of Process Data, even though we didn't follow the input schema exactly. We only get what was under WebservicesResponseNode. Now, let's do some validation enforcement. We will start with just the inbound schema. Go edit the BP Schema Mapping and set the checkbox for Input Validation and save. Then post your request again.

This time when posting a request, a fault is generated. Here's an excerpt from the response:

<SOAP-ENV:Fault xmlns:mesa="http://www.sterlingcommerce.com/mesa">
<faultcode>SOAP-ENV:Receiver</faultcode>
<faultstring>Fault occurred in processing, detail provided.</faultstring>
<detail>
<mesa:faultDetail>id= 31161 stepId=10 serviceName=SOARequestHandler_Instance message=Service Specific Exception (check status report) runTime=2014.07.28 12:00:00.0</mesa:faultDetail>
</detail>
</SOAP-ENV:Fault>

This provides a workflow ID and step number for the SOA Request Handler. If I go check the status report there:

cvc-pattern-valid: Value '12345' is not facet-valid with respect to pattern '[a-zA-Z0-9]{8}' for type '#AnonType_customerId'

which is absolutely correct. Providing an 8 digit alpha-numeric makes the fault go away.

Now let's turn on the output validation. Edit the schema mapping again, and enable the output validation in the same way you did the input validation, then re-post a document. Again, we run into an error, this time in the SOA Response Builder:

cvc-elt.1: Cannot find the declaration of element 'NameData'

But why is this? We have it right in the schema. The answer is that it is looking for a NameData node associated with the targetNamespace. But, in order to find that node, we have to assign to a namespace prefix within Process Data, and to do that, we have to add the namespace to our environment through the namespaces.properties file (or customer_overrides, which I'll use). Once you've entered the namespace into the property file, you can refresh namespaces by following instructions here:

http://www-01.ibm.com/support/knowledgecenter/SS3JSW_5.2.0/com.ibm.help.web_services.doc/SI_NS_ModNamespc.html?lang=en

If you want to double-check its been loaded, you can do so by looking at namespaces.properties entries through the queueWatcher screen.

I entered the following into customer_overrides.properties, and then used the opsCmd to reload namespaces as specified in the linked article above:

namespaces.ibmws_out=http://www.sterlingcommerce.com/ibmws_out

The last change we will make for the output is to modify the BP to use this namespace. We have to add it to all nodes in the path that will be generated under the target namespace:

<process name="BSWS_NameLookup">

<sequence>
<operation name="AssignService">
<participant name="AssignService"/>
<output message="AssignOutputMessage">
<assign to="." from="*"/>
<assign to="WebservicesResponseNode/ibmws_out:NameData/ibmws_out:Prefix">Mr.</assign>
<assign to="WebservicesResponseNode/ibmws_out:NameData/ibmws_out:FirstName">Brian</assign>
<assign to="WebservicesResponseNode/ibmws_out:NameData/ibmws_out:LastName">Sak</assign>
</output>
<input message="AssignInputMessage">
<assign to="." from="*"/>
</input>
</operation>
</sequence>
</process>

These assigns would be impossible if we hadn't added the namespaces to the property file.

Now, after making the new version of the business process the default, and reposting our document, we see results that have the target namespace included and the document has been validated according to the schema. Output validation is less common than input validation since you have more control over the results being sent back than the requests being posted. However, if you find that the response you are generating could provide unexpected results, an output schema can verify that you are sending valid information back to the partner.

Here's a screenshot of the new, validated output:

image

At this point, we now have a complete web service that takes a request, validates the input, generates some output, which is then validated and returned to the partner.

In the next blog post, we will use this web service provider to help us to learn about dynamic services when Sterling B2B Integrator is acting as the consumer. Based on the WSDL, we'll generate some new BP participants which will automatically consume this service. See you next time!

[{"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SS3JSW","label":"IBM Sterling B2B Integrator"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB59","label":"Sustainability Software"}}]

UID

ibm11122105