Version 9.6
 —  Virtualized Services in CentraSite Control  —

Important Considerations when Configuring REST or XML Virtual Services

With Web services, the native service endpoint that is sent by CentraSite to Mediator inside a virtual service definition is a static element. Once the virtual service is successfully deployed to Mediator, the real endpoint is returned to CentraSite as part of the response message during deployment. At run time, when a SOAP request is received, that request is POSTed to the endpoint that is statically defined in the virtual service definition.

With REST services or XML services, however the endpoint is flexible. The REST services or XML services describe data as resources. The resources are accessible via logical endpoints that have application meaning to users. For example, a collection of textbooks might be defined as a resource with the following URL:

http://{host}:{port}/books

A specific book with an identifier of 1234 would be accessible with the following URL:

http://{host}:{port}/books/1234 

Due to this difference and others, you should keep the following topics in mind when you configure a REST or XML virtual service:


Endpoint Manipulation of REST or XML Virtual Services

When you configure the processing steps of a virtual REST or XML service, you specify the native service name, an endpoint, and the HTTP method type(s) that are included in the message (POST, GET, PUT, DELETE). From this information, CentraSite will generate a virtual service definition that includes service and operation elements, as well as an endpoint and binding element pair for each HTTP method specified.

CentraSite will automatically generate an operation name to be included when the virtual service definition deployment message is sent to Mediator. This means that if you create a virtual service called VS1, and you specify a native endpoint, then the endpoint exposed by Mediator for calling the virtual service will be /ws/VS1/Invoke.

For example, assume the following endpoints are deployed.

Native service endpoint: http://localhost:8080/services/mtc/member
Virtual service endpoint: http://localhost:5555/ws/VS1/Invoke

Assume that the example virtual service is deployed with two HTTP method bindings: GET and POST. Both of these bindings have operation elements that include the same HTTP location attribute: member. To better illustrate the functionality, the examples below show a series of sample requests from a consumer including the requests' HTTP method and Content-Type. (At run time, REST message detection is dependent upon a consumer using the correct Content-Type when a request is sent.) Each example shows the expected endpoint that Mediator will send after it has rewritten the endpoint prior to native service invocation.

Example 1

For a GET, assume that:

The request Content-Type is: application-x-www-form-urlencoded

The endpoint received by Mediator is: http://localhost:5555/ws/VS1/Invoke

The native service endpoint sent by Mediator is: http://localhost:8080/services/mtc/member

The application function is: The native service returns a collection of members with summary information.

Example 2

For a GET, assume that:

The request Content-Type is: application-x-www-form-urlencoded

The endpoint received by Mediator is: http://localhost:5555/ws/VS1/Invoke/1234

The native service endpoint sent by Mediator is: http://localhost:8080/services/mtc/member/1234

The application function is: The native service returns summary data for a member with this key.

Example 3

For a GET, assume that:

The request Content-Type is: application-x-www-form-urlencoded

The endpoint received by Mediator is: http://localhost:5555/ws/VS1/Invoke/1234?detail=true

The native service endpoint sent by Mediator is: http://localhost:8080/services/mtc/member/1234?detail=true

The application function is: Query parameters remain intact. Returns a response message with more member details.

Example 4

For a POST, assume that:

The request Content-Type is: application/xml or application/json

The endpoint received by Mediator is: http://localhost:5555/ws/VS1/Invoke/1234

The native service endpoint sent by Mediator is: http://localhost:8080/services/mtc/member/1234

The application function is: The request message provides the contents needed to create the member resource.

Example 5

For a GET, assume that:

The request Content-Type is: application-x-www-form-urlencoded

The endpoint received by Mediator is: http://localhost:5555/ws/VS1/Invoke/joe

The native service endpoint sent by Mediator is: http://localhost:8080/services/mtc/member/joe

The application function is: Fetches the member defined with the login joe. (Mediator contains no metadata in its service deployment to differentiate between the "login" vs. "key" GET requests.)

Example 6

For a GET, assume that:

The request Content-Type is: application-x-www-form-urlencoded

The endpoint received by Mediator is: http://localhost:5555/ws/VS1/Invoke?type=login&value=joe

The native service endpoint sent by Mediator is: http://localhost:8080/services/mtc/member?type=login&value=joe

The application function is: The native service might also support a static endpoint with constraints defined in query parameters. Mediator also supports this approach.

Top of page

The Request Message’s HTTP Methods and Content-Types for REST and XML Services

When you configure the Entry Protocol step of a virtual REST or XML service, it is important to specify all the HTTP methods that are supported for the service. For example, if the virtual service is deployed to Mediator and you selected only the GET method in the virtual service's Entry Step, then Mediator will only permit GET invocations. In this case, a POST request will be rejected with a return of statusCode 405 even if the native service happens to support POSTs.

It is important that the client's requests contain an HTTP Content-Type header. At run time, Mediator determines which message builder to use based on the message’s HTTP method and its Content-Type. (The absence of the soapAction header will indicate to Mediator that the message is an XML message.)

The valid HTTP method/Content-Type combinations are as follows:

This method... Can be included in a message of this Content-Type...
POST application/xml
application/json
application-x-www-form-urlencoded
multipart/form-data
or text/xml
PUT application/xml
application/json
application-x-www-form-urlencoded
multipart/form-data
or text/xml
GET application-x-www-form-urlencoded
DELETE application-x-www-form-urlencoded

Notes:

  1. If Mediator receives a request sent with an HTTP method that is not specified in the virtual REST service or virtual XML service definition, it will return a 405 error.
  2. If Mediator receives a request sent with a wrong Content-Type, it will return a 415 error. In addition, if the wrong Content-Type is used with a GET or DELETE, then the query parameters contained in the message (if any) will not be processed.

Top of page

Changing the HTTP Method of a REST or XML Request

When configuring the routing step of a REST or XML virtual service, you specify whether to route the requests to the native service with the same HTTP method that is contained in the requests (GET, POST, PUT, DELETE), or whether to route the requests with a different HTTP method.

Typically you want to pass each request to the native service with the same HTTP method that is contained in the request. For example, if a request contains a GET method, you allow the GET method to be passed to the native service. However, there might be rare cases in which you want to change the HTTP method of a request to different HTTP method. For example, you might want to:

Start of instruction setTo change the HTTP method of a REST or XML request

Caution:
Use this feature carefully, since changing HTTP methods to certain other HTTP methods could result in unintended results or errors.

For example, changing an inbound GET request to a DELETE request would be a serious mistake if the deletion was not intended and the native REST service actually deleted a resource when invoked with a DELETE method. Additionally, an incoming POST or PUT request cannot be translated into a GET or DELETE if the request has nested elements. For more information, see The Implications of Changing HTTP Methods.

This section discusses the following topics:

The Implications of Changing HTTP Methods

Note the following.

When changing this incoming HTTP method... To... Note that...
GET POST
  • The Content-Type of the changed request is sent as application/xml or application/json, and the charset is UTF-8.

  • Depending on the structure of the native service, be aware that the native service might not be expecting the same payload structure that is being sent. In this case, you would need to transform the request message into the format required by the native service before Mediator sends the requests to the native service. For more information, see Sample XSLT Transformation for GET-to-POST or GET-to-PUT.

GET PUT Identical to GET-to-POST, except that Mediator changes the request's HTTP method from GET to PUT.
GET DELETE No comment.
POST GET
  • Mediator will translate the POSTed request elements into query string parameters, in a root element.

    Note:
    An incoming POST or PUT request cannot be translated into a GET or DELETE if the request has nested elements. For example:

    (this is correct)
    <person>
      <lastName>Smith</lastName>
     </person>
    
    (this is incorrect)
    <person>
      <name>
          <last>Smith</last>
       </name>
    </person>
    
  • If you want to send additional parameters as part of the request URL, you can transform this payload. To do this, you can use an XSLT file or a webMethods IS service call to add parameters before the request is sent to the native service. For more information, see The Request Processing Step.

POST DELETE Identical to POST-to-GET, except that Mediator changes the request's HTTP method from POST to DELETE.
POST PUT The Content-Type of the changed request is sent as application/xml or application/json, and the charset is UTF-8.
PUT GET Identical to POST-to-GET, except that Mediator changes the request's HTTP method from PUT to GET.
PUT POST The Content-Type of the changed request is sent as application/xml or application/json, and the charset is UTF-8.
PUT DELETE Identical to POST-to-DELETE, except that Mediator changes the request's HTTP method from PUT to DELETE.
DELETE GET No comment.
DELETE POST Identical to GET-to-POST, except that Mediator changes the request's HTTP method from DELETE to POST.
DELETE PUT Identical to GET-to-PUT, except that Mediator changes the request's HTTP method from DELETE to PUT.
GET, POST, PUT or DELETE Use Context Variable See Changing HTTP Methods in Requests Dynamically using a Context Variable.
GET or DELETE POST or PUT Note that the query parameters will be picked off the URL and stored as top-level elements when the message is sent to the native service. The query parameters are ignored on the endpoint URL and lost when we POST to the native provider (i.e. don't change the protocol method).

Changing HTTP Methods in Requests Dynamically using a Context Variable

Alternatively, instead of changing an HTTP method explicitly (statically) to PUT, POST, GET or DELETE, you can change the HTTP method to the value of a predefined context variable (ROUTING_METHOD) that dynamically resolves to a different HTTP method (PUT, POST, GET or DELETE, as appropriate).

To change the HTTP method dynamically, you create a webMethods IS service and invoke it in the virtual service's Request Processing step. This webMethods IS service should reference the predefined context variable ROUTING_METHOD (see The Predefined Context Variables). To set the value of ROUTING_METHOD, use the setContextVariableValue method, which is defined in the following class:

com/softwareag/mediator/api/MediatorRuntimeFacade.java

For example:

public static final void updateHttpMethod(IData pipeline)
			throws ServiceException {
	
String mcKey = “Message Context”;
		
	Object obj = IDataUtil.get(pipeline.getCursor(), mcKey);
	if (obj!=null && obj instanceof 
org.apache.axis2.context.MessageContext) {
			
		MessageContext msgCtx = (MessageContext) obj;
			
QName varName =  
new QName(MediatorContextVariableType.ROUTING_METHOD.getName());
	
MediatorRuntimeFacade.setContextVariableValue(varName, "PUT", msgCtx ); 
	}	
}

Sample XSLT Transformation for GET-to-POST or GET-to-PUT

As stated in the above table, depending on the structure of the native service, the native service might not be expecting the same payload structure that is being sent. In this case, you would need to transform the request message into the format required by the native service before Mediator sends the requests to the native service. To do this, you invoke an XSLT file during the Request Processing step.

Assume that:

Following is a sample XSLT transformation file for the GET-to-POST or GET-to-PUT scenario.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns="http://example.com/authors"
    version="1.0">    
    
    <xsl:output method="xml" omit-xml-declaration="no" standalone="yes" indent="yes"/>
    
    <xsl:strip-space elements="*"/>    
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="//ns:invoke/node()">
        <xsl:element name="{local-name(.)}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="//ns:invoke">
        <xsl:element name="authors">
            <xsl:apply-templates/>
        </xsl:element>        
    </xsl:template>
</xsl:stylesheet>

Top of page

Working with the JSON Content-Type

Mediator can accept a REST service request that specifies the Content-Type "application/json" (or "application/json/badgerfish") and the HTTP methods PUT, GET, DELETE and POST.

Assuming that the native service supports both JSON and the HTTP method(s) specified in the request, Mediator can determine the correct service, operation and output format (JSON) to return to the consuming application. There are different ways in which a native service provider can be prompted to return response content. It will vary with the provider. For example, some providers may rely on the Accept transport header to specify the format the consumer wants. Others may use an element in the request or a query parameter on the URL.

However, suppose for example that the native service does not support the HTTP method specified in the request (e.g., POST). As a workaround, you can configure the virtual service so that it "bridges" this difference between the consumer request and the native service. In this case, you can configure the virtual service so that it takes the POST and bridges it into an HTTP GET query, and then returns the service to the consumer in the expected JSON format. To implement this, you set the following predefined context variables in a user-defined webMethods IS service that you can invoke in the virtual service’s Request Processing step and Response Processing step:

This and other "bridging" scenarios are discussed in more detail below.

How Mediator Determines Which Builder and Formatter Classes to Use (and How You Can Override Them)

Mediator makes these determinations at run time as follows. This table also summarizes how you can override the default determinations.

Run-time Step Description
Mediator receives the request from the client

It is important that the client's PUT or POST requests contain the HTTP header Content-Type because the Content-Type header determines the message builder Mediator uses to parse the input stream. (GET or DELETE request do not require a Content-Type header.)

Mediator sends the request to the service provider

Mediator uses a message formatter to serialize the request, and then sends the serialized request to the native service provider.

Mediator determines the message formatter to use as follows:

  • If you explicitly specify a message formatter (by setting the MESSAGE_TYPE context variable in a webMethods IS service and invoking this service in the virtual service’s Request Processing step), then Mediator uses that formatter. The Content-Type header that Mediator sends to the native provider is the one that is associated with the MESSAGE_TYPE context variable.

  • Else, Mediator will use the message formatter associated with the Content-Type sent by the client (and sends the Content-Type to the native provider).

  • Else, if no Content-Type was sent by the client, then:

    • For PUT requests, the default formatter used (and the Content-Type header that Mediator sends to the native provider) is application/xml.

    • For POST requests, the default formatter used (and the Content-Type header that Mediator sends to the native provider) is SOAP (and the request will fail).

    • For GET or DELETE requests (which do not require a Content-Type header), the default formatter used (and the Content-Type header that Mediator sends to the native provider) is application/x-www-form-urlencoded.

Mediator receives a response from the service provider

When the provider returns a response to Mediator, a message builder parses the response stream into an Axiom message to be stored in the message context. Mediator determines which message builder to use as follows:

  1. Mediator will select the message builder associated with the request's Accept transport header, if one was specified.

  2. Else, you can set the BUILDER_TYPE context variable in a webMethods IS service, and invoke this service in the virtual service’s Request Processing step. Mediator will check that the builder type is a valid Content-Type for the list of builders in axis2.xml. This variable takes priority over the current setting specified in the Accept transport header. That is, Mediator will only use the Accept header to determine the builder type needed to parse a native provider response if no IS service was written to set the BUILDER_TYPE context variable.

  3. Else, Mediator will use the builder associated with the Content-Type specified in the request (assuming that the Content-Type is one of the types that is mapped in axis2.xml).

  4. Else, if no Content-Type was specified in the request (e.g., a PUT or POST request with no Content-Type, or any GET or DELETE request), or if the Content-Type is not one of the types that is mapped in axis2.xml, then Mediator will default to application/xml.

Mediator sends a response to the client

Mediator serializes the response and sends it to the client.

By default, Mediator uses the formatter that was used to serialize the request sent to the provider. (If the formatter was application/x-www-form-urlencoded (for a GET or DELETE request), then Mediator will instead use application/xml so it can send the response.)

You can override the Content-Type that is sent to the client by setting the MESSAGE_TYPE context variable in a webMethods IS service, and invoking this service in the virtual service’s Response Processing step.

Scenarios for Requesting JSON Type Services

Following are some of the possible scenarios in which JSON type services can be requested. Many scenarios require that you "bridge" the differences between consumer requests and the native service (i.e., differing HTTP methods and Content-Types). Three of the scenarios are discussed in more detail following the table.

Consumer Sends Mediator Sends Request to Provider Mediator Receives Response from Provider Mediator Sends Response to Consumer Requirement for Bridging?
GET GET JSON JSON Request Processing step bridging (see JSON Example 1: GET Request, JSON Response)
POST/JSON POST/JSON JSON JSON No bridging needed
GET GET XML JSON Response Processing step bridging
POST/JSON GET JSON JSON Request Processing step bridging
POST/JSON GET XML JSON Request Processing step bridging and
Response Processing step bridging
(see JSON Example 2: POST/JSON Request, JSON Response (where POST is not supported))
POST/JSON XSLT/GET * JSON JSON Request Processing step bridging
POST/JSON XSLT/POST/XML * XML XML Request Processing step bridging
POST/JSON POST/JSON JSON/XSLT * JSON Response Processing step bridging
GET GET JSON XML Request Processing step bridging and
Response Processing step bridging
(see JSON Example 3: GET Request, XML Response)
POST/XML POST/JSON JSON JSON Request Processing step bridging

* The XSLT references indicate where you can perform an XSLT message transformation at either the Request Processing or Response Processing step.

In the table above, the required Content-Type settings are not shown, but assume the following:

HTTP Method/Request Content Required Axis2 Content Type
GET or DELETE application/x-www-form-urlencoded
POST or PUT/XML application/xml
POST or PUT/Mapped JSON application/json
POST or PUT/Badgerfish application/json/badgerfish

JSON Example 1: GET Request, JSON Response

In this example, a consumer sends a GET request to get a native JSON service. Mediator will send the response to the consumer in the requested JSON format (as indicated by the "output=json" parameter in the query).

The request looks like this:

http://localhost:5555/ws/YahooVS/search?query=wsdl20&output=json

and because this is a GET request, the Content-Type defaults to application/x-www-form-urlencoded.

Note:
For GET or DELETE requests for REST services, it is not necessary to specify the Content-Type in the request; Mediator will default to application/x-www-form-urlencoded for GET or DELETE requests.

The run-time processing will be as follows:

Consumer Sends Mediator Sends Request to Provider Mediator Receives Response from Provider Mediator Sends Response to Consumer Requirement for Bridging
GET GET JSON JSON Request Processing step bridging

Since the request is a GET (i.e., of Content-Type application/x-www-form-urlencoded), but Mediator expects to receive a JSON stream from the provider, you must send the BUILDER_TYPE application/json to the native provider. To do this, write and invoke a webMethods IS service in the virtual service’s Request Processing step. The IS service should include the following predefined context variable set to this value:

Context Variable Value
BUILDER_TYPE application/json

JSON Example 2: POST/JSON Request, JSON Response (where POST is not supported)

In this example, a consumer sends a POST request (of Content-Type application/json) to a native service, but the native service does not support POST.

The request's Content-Type is application/json and its output parameter is set to xml. The reason for this is explained below.

The run-time processing will be as follows:

Consumer Sends Mediator Sends Request to Provider Mediator Receives Response from Provider Mediator Sends Response to Consumer Requirement for Bridging
POST/JSON GET XML JSON
  • Request Processing step bridging

  • Response Processing step bridging

Configure the virtual service as follows:

JSON Example 3: GET Request, XML Response

In this example, a consumer sends a GET request to get a native service. Mediator will send the response to the consumer in the requested XML format (as indicated by the "output=xml" parameter in the query).

The request looks like this:

http://localhost:5555/ws/YahooVS/search?query=wsdl20&output=xml

and because this is a GET request, the Content-Type defaults to application/x-www-form-urlencoded.

The run-time processing will be as follows:

Consumer Sends Mediator Sends Request to Provider Mediator Receives Response from Provider Mediator Sends Response to Consumer Requirement for Bridging
GET GET JSON XML
  • Request Processing step bridging

  • Response Processing step bridging

Since the request is a GET (i.e., of Content-Type application/x-www-form-urlencoded), but Mediator expects to receive a JSON stream from the provider, you must instruct Mediator to send the BUILDER_TYPE application/json to the native provider. To do this, write and invoke a webMethods IS service in the virtual service’s Request Processing step. The IS service should include the following predefined context variable set to this value.

Context Variable Value
BUILDER_TYPE application/json

Since the provider will return a JSON stream to Mediator, but the consumer expects to receive the service in XML output format, you must set the MESSAGE_TYPE to application/xml. To do this, write and invoke a webMethods IS service in the virtual service’s Response Processing step. The IS service should include the following predefined context variable set to this value:

Context Variable Value
MESSAGE_TYPE application/xml

Characteristics of the Mapped and Badgerfish JSON Conventions

The open source library that Axis2 uses to support JSON is called Jettison. The Jettison library supports two formats of JSON: Mapped JSON and Badgerfish. Both are syntactically correct from a JSON perspective.

Note:
An important difference between the two is that the Mapped convention returns a service fault if a virtual service is configured for application/json (Mapped convention) and it encounters a message that has namespaces, while the Badgerfish convention attempts to avoid losing any meaning encoded in XML by preserving namespace declarations. The Axis2 JSON library MessageFormatter will complain if Mediator attempts to transform an XML response that contains namespace declarations. So, either make sure that the requests do not include namespaces, or else set the MESSAGE_TYPE to application/json/badgerfish instead of setting it to application/json.

Other characteristics include the following.

Mapped JSON Convention

  1. An element with no characters or child elements is represented by:

    { "element" : "" }

  2. No namespaces declarations are ever written.

    Note:
    The Badgerfish convention does allow namespaces. If a client sends a request that contains XML namespaces, you need to bridge to the Badgerfish convention. To do this, in the virtual service's Routing Protocol's step, set the parameter HTTP Headers to Customize and specify the Name as "Content-Type" and the Value as "application/json/badgerfish". Doing this will override the existing Content-Type that will be sent to the native provider.

  3. An element with multiple child elements of the same name is represented by an array.

    Simple case:

     <price>10.00</price>
     { "acme.price" : { "10.00" }
    

    Array case:

     <root><child>test</child><child>test</child></root>
     { "root" : { "child" : [ "test", "test" ] } }
    
  4. The XML attributes for a message are prefixed with @ when a message is serialized (same as Badgerfish).

Badgerfish Convention

This convention is used to provide the means to translate between XML and JSON without losing any data (i.e., namespaces).

  1. Element names become object properties.

  2. Text content of elements goes in the $ property of an object.

  3. Nested elements become nested properties.

  4. Multiple elements at the same level become array elements.

  5. Attributes go in properties whose names begin with @.

  6. Active namespaces for an element go in the element's @xmlns property.

  7. The default namespace URI goes in @xmlns.$.

  8. Other namespaces go in other properties of @xmlns.

  9. Elements with namespace prefixes become object properties, too.

    Simple example:

    
     <price xmlns="http://acme.com">10.00</price>
    { "price": { "@xmlns": { "$": "http://acme.com" }, "$1": "10.00" } }
    

    A more complex example:

    <alice xmlns="http://some-namespace" xmlns:charlie="http://some-other-namespace">
      <bob>david</bob>
      <charlie:edgar>frank</charlie:edgar>
    </alice>
    
    { "alice" : { "bob" : { "$" : "david" , "@xmlns" : {"charlie"  :  "http:\/\/some-other-namespace" , "$" : "http:\/\/some-namespace"} } ,               "charlie:edgar" : { "$" : "frank" , "@xmlns"  : {"charlie":"http:\/\/some-other-namespace", "$" :  "http:\/\/some-namespace"} },               "@xmlns" : { "charlie" : "http:\/\/some-other-namespace",  "$" : "http:\/\/some-namespace"} } }
    

Multiple Root Nodes in JSON REST Services

With REST virtual services, when working with requests and responses of the Content-Type application/json, the message content can contain one or more root nodes. For example, a message might have the two root nodes {“firstName": “John”, “lastName”: “Smith”}. Note the following points for messages with multiple root nodes.

Top of page