Custom Transport - HTTPService with Error Handling

This is an evolving project that is looking at features that may need to added to the basic HTTP Transport to handle a variety of different use cases.  The scenarios that we have identified and implemented are:

  1. Handling services that return responses other than 200
  2. Omitting empty XML elements from the request-entity
  3. Submitting form data in the request-entity (simulate a basic HTML form)

There may be other scenarios that require additional features that we will review and consider as they are identified.

Rebuilt for 8.6.2 - HTTPWithErrorSupportService.jar

This article is provided as a demonstration of how you could extend the existing functionality.  You can either choose to use the custom code that is provided or you can write your own.  The code is provided *as-is* by the author and there is no support agreement.  If you do identify issues or have additional cases that you would like covered raise them through comments or forum posts and we can consider implementing them.


Transport ID - HTTPServiceTransport.WithErrorSupport

This transport adds the following parameters (all the default HTTPServiceTransport parameters still apply):


Input ParameterDescription
response-allowed-error-codes

Sometimes you may submit to a service that returns a response code that is not 200, in those cases the HTTPServiceTransport will interpret the request as an error and show an error in your FEB app.  The purpose of this custom transport is to extend the default HTTPServiceTransport and capture the response code from the service we communicated with but return 200 to FEB so that it does not throw a run-time error.


Space-delimited list of all the error codes that will be intercepted by this transport.  If note specified then the response code will be returned directly to FEB without being changed.

You can use '*' to intercept all response codes.

You can specify specific codes to intercept (i.e. 201, 404, etc)

response-on-error-body

This will overwrite the response-entity with the content specified.

Examples

response-on-error-body201 - overwrite if response code is 201

response-on-error-body* - overwrite for all response codes

omit-empty-params-from-request

Valid values are true and false.  If true, then any empty XML elements will be removed from the request-entity: <a/> or <a></a>.  This was required because of a limitation in the basic  HTTPServiceTransport (8.6.2).  Empty input values will create empty nodes in the request-entity, some services fail if these empty nodes are present.  This feature will strip out all the empty nodes.


For example, A mapping like this:


<mapping sourceType="NOOP" target="transport:request-entity" targetType="XML">
  <mapping source="parameter:title" sourceType="STRING" targetRef="a:entry/a:title"/>
  <mapping source="parameter:event-content" sourceType="STRING" targetRef="a:entry/a:content"/>

</mapping>


If your input parameters are empty the request entity might look like:

<title/><content></content>

These parameters will be stripped from the request-entity if set to true.

request-entity-formData-paramName

There basic HTTPServiceTransport (8.6.2) does not provide any mechanism for passing form parameters as the request entity.  This prefix was added to this custom transport to provide that capability of simulating an HTML form.  Replace paramName with the name of the parameter to be sent in the request body.


For example, the following mappings:

<mapping target="transport:request-entity-formData-company" source="parameter:company" sourceType="STRING" targetType="STRING"/>
<mapping target="transport:request-entity-formData-email" source="parameter:email" sourceType="STRING" targetType="STRING"/>


With result in the following being sent as the request body:

company=IBM&email=cdawes@ca.ibm.com


This property can be used with omit-empty-params-from-request, if specified then empty params will be omitted from the request.

request-entity-formData-paramName-encoded

Valid values are true and false. Flag indicating whether the value is encoded. If this parameter is missing or is set to true, the value is URL encoded. To not encode the parameter values set to false.  Specify for each parameter to which you want it applied.


Mappings do not allow assigning text values, therefore you must define a constant or parameter to map the "true" or "false"

For Example:


<constant>
     <id>encodedVal</id>
     <value>false</value>
</constant>

<mapping target="transport:request-entity-formData-retURL-encoded" source="constant:encodedVal" sourceType="STRING" targetType="STRING"/>
Output ParameterDescription
response-codeSet to the error code that was detected from calling the service.
response-entitySet to the message that was provided from the input parameter but it will be wrapped in an XML tag, i.e. <response-entity> the message </response-entity>


Usage:

1. Set the transport id:

<?xml version="1.0" encoding="UTF-8"?>
<serviceDescription>
    <id>CallHTTPService</id>
    <defaultLocale>en</defaultLocale>
    <transportId>HTTPServiceTransport.WithErrorSupport</transportId>
    <name xml:lang="en">Call HTTP Service</name>
    <description xml:lang="en"/>

2. Specify the constants/parameters for the transport parameters:

<constant>
                <id>allowed-error-codes</id>
                <value>201</value>
            </constant>
            <constant>
          <id>on.error.entity.body</id>
          <value></value>
        </constant>

3. Create the service mappings to link the constants to the transport variables:


<mapping xmlns="">
                <mapping target="transport:response-allowed-error-codes" source="constant:allowed-error-codes"></mapping>
                <mapping target="transport:response-on-error-body201" source="constant:on.error.entity.body" targetType="STRING" />

</mapping>


4. Create the outbound parameters and mappings:

<parameters>
            <parameter>
                <id>status</id>
                <name xml:lang="en">Status</name>
                <description xml:lang="en"></description>
                <type>STRING</type>
            </parameter>
            <parameter>
                <id>response-body</id>
                <name xml:lang="en">Response</name>
                <description xml:lang="en"></description>
                <type>STRING</type>
            </parameter>
        </parameters>
        <serviceMapping>
            <mapping>
                <mapping source="transport:response-code" target="parameter:status" sourceType="STRING" targetType="STRING"></mapping>
                <mapping source="transport:response-entity" sourceRef="response-entity" target="parameter:response-body" sourceType="XML" targetType="STRING"></mapping>
            </mapping>
        </serviceMapping>

Note: The transport:response-code will be the original response code from calling the service.  The message will be returned as XML wrapped by "<response-entity>" element.  As you can see, now you can provide customized messages to your FEB application based on the response code returned from the service you are integrating with.

Many of the Connections service descriptions require this transport because of their non-200 return values.