Try WSO2 Cloud for Free
Sign in
||
Skip to end of metadata
Go to start of metadata

The following is a list of examples, explaining how you can use mediation sequences with your APIs in WSO2 API Cloud.

The custom sequences given below can be added to your API through the Publisher UI. See Add a Custom Sequence to your API, for instructions on how to do this.

Changing the content type

The following are two examples on how to convert your message.

Convert an XML message to JSON

To convert an XML message to JSON, add the messageType property to the custom sequence as shown in the sample below.

<sequence xmlns="http://ws.apache.org/ns/synapse"  name="xml_to_json_message">      
    <property name="messageType" value="application/json" scope="axis2"/>
</sequence>

This sequence can be added in the In flow and the Out flow.

The following sequences are available in WSO2 API Cloud by default. See Add a Custom Sequence to your API for instructions on adding this to your API.

  • In Flow - xml_json_in_message
  • Out Flow - xml_json_out_message

The diagram below shows how this fits into an API call as a custom sequence.

Convert a JSON message to XML

To convert a JSON message to XML, add the messageType property to the custom sequence as shown in the sample below.

<sequence xmlns="http://ws.apache.org/ns/synapse"  name="json_to_xml_message">      
    <property name="messageType" value="application/xml" scope="axis2"/>
</sequence>

This sequence can be added in the In flow and the Out flow.

The following sequences are available in WSO2 API Cloud by default. See Add a Custom Sequence to your API for instructions on adding this to your API.

  • In Flow - json_xml_in_message
  • Out Flow - json_xml_out_message

The diagram below shows how this fits into an API call as a custom sequence.

Extracting, transforming or replacing the contents of a message

This example shows how to use custom sequences to

  • Change the existing attributes of a message

  • Create a new message

  • Add new attributes to a message.

  • Remove attributes from a message

For more information, see PayloadFactory Mediator.

Manipulating an XML message

This sequence can be added to your In flow as well as your Out flow. A sample custom sequence is given below.

<sequence xmlns="http://ws.apache.org/ns/synapse"  name="message_transform_xml">        
  <!-- Here you specify the format of the json message you need to output -->
     <payloadFactory media-type="xml">
            <format>
	      <userdata>
		<username>$1</username>
		<age>$2</age>
	      </userdata>
            </format>
              <!-- Used to extract the elements from the XML payload and then assigns them to the variables $1 and $2 respectively. First argument is assigned to the variable $1 and the second to $2-->
            <args>
               <arg expression="//user/name" evaluator="xml"/>
               <arg expression="//user/age" evaluator="xml"/>
            </args>
</payloadFactory>
  <property name="messageType" value="application/xml" scope="axis2"/>
</sequence>

The diagram below shows how this sequence fits in to the Out flow.

Manipulating a JSON message

This sequence can be added to your In flow as well as your Out flow. A sample custom sequence is given below.

<sequence xmlns="http://ws.apache.org/ns/synapse"  name="message_transform_json">        
     <payloadFactory media-type="json">
  <!-- Here you specify the format of the json message you need to output -->
            <format>
             {  "userdata":  
                {
                    "username": "$1",
                    "age": "$2"
                }
             }
            </format>
           <!-- Used to extract the elements from the JSON payload and then assigns them to the variables $1 and $2 respectively. First argument is assigned to the variable $1 and the second to $2-->
            <args>
               <arg expression="$.user.name" evaluator="json"/>
               <arg expression="$.user.age" evaluator="json"/>
            </args>
</payloadFactory>
  <property name="messageType" value="application/json" scope="axis2"/>
</sequence>

The diagram below shows how this sequence fits in to the Out flow.


Adding headers

You can add custom headers to your sequences.

Adding a custom header

Headers are added to the sequence using the header mediator. You can set a name for the header and the scope as transport, as shown in the example below.

 <header name="customHeader" scope="transport" value="test"/>

To add this custom header to your sequence, save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.

<sequence xmlns="http://ws.apache.org/ns/synapse" name="header_sequence">
   <header name="customHeader" scope="transport" value="test"/>
</sequence>

Passing an authorization header to your backend


You cannot directly create an authorization header with the name Authorization, in the API Cloud as the keyword Authorization is a reserved header name. The following is an alternative to add a header with this name. 

  • Pass the value you need to be set as the Authorization header in a property named X-Authorization.
  • Extract the value of X-Authorization and set it as the Authorization property inside your custom sequence.
  • Drop the additional X-Authorization header,

Now the Authorization property will be received by your backend with the value you initially passed in the X-Authorization header.  The sample is given below.

<sequence xmlns="http://ws.apache.org/ns/synapse" name="authorization_header_exchange">
    <property name="X-Authorization" expression="get-property("'transport', 'X-Authorization')" scope="default" type="STRING"/>
    <property name="Authorization" expression="get-property('X-Authorization')" scope="transport" type="STRING" description=""/>
    <property name="X-Authorization" scope="transport" action="remove"/>
</sequence>

The following sequence is available in WSO2 API Cloud by default. See Add a Custom Sequence to your API for instructions on adding this to your API.

  • In Flow - authorization_header_exchange

Filtering messages

Filtering messages using a single condition

The Filter Mediator can be used to filter messages based on an XPath, JSONPath or a regular expression. If the test succeeds, the Filter mediator executes other mediators enclosed in the sequence. This acts as an if-else condition in java.

Syntax
<filter (source="[XPath|json-eval(JSONPath)]" regex="string") | xpath="[XPath|json-eval(JSONPath)]">
   mediator+
</filter>

This example shows how to check if the request parameter matches a certain string and print a message if it matches correctly (the path parameter countryCode, passed in a request)

Request
https:/gateway.api.cloud.wso2.com:443/t/wso2cloud/countries/us

Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.

<filter source="get-property('uri.var.countryCode')" regex=".*us">
   <then>
      <log level="custom">
         <property name="country" value="Details of USA are requested"/>
      </log>
   </then>
   <else>
      <log level="custom">
         <property name="service" value="Details of a different country is requested"/>
      </log>
   </else>
</filter>

Filtering messages using a series of conditions 

Using custom sequences, you can evaluate a value passed through the API or check against a series of multiple conditions and then execute the relevant logic. This custom mediation behaves in the same way as a switch statement in java. This string is matched against the regular expression in each switch case mediator, in the specified order. If a matching case is found, it will be executed, and the remaining switch case mediators are not processed. If none of the case statements are matching, and a default case is specified, the default will be executed.

Syntax
<switch source="[XPath|json-eval(JSON Path)]">
   <case regex="string">
     mediator+
   </case>+
   <default>
     mediator+
   </default>?
</switch>

The following example shows how to switch based on the request URI invoked through your API. If the particular condition is satisfied it will print a log message to the live log viewer. Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.

<sequence name="switch_conditions" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
	<switch source="get-property('To')">
    	<case regex=".*/countries/.*">
        	<log level = "custom">    
            	<property name="value" value="countries operation is executed"/>
       		</log>
        	<!-- logic if it satisfies this condition ie if the request is for the request uri /countries -->
    	</case>
    	<case regex=".*/regions/.*">
        	<log level = "custom">
        	 	<property name="value" value="regions operation is executed"/>
        	</log>
        	<!-- logic if it satisfies this condition ie if the request is for the request uri /region -->
    	</case>
        <case regex=".*/capital/.*">
        	<log level = "custom">
        	 	<property name="value" value="capital operation is executed"/>
            </log>
        	<!-- logic if it satisfies this condition ie if the request is for the request uri /capital -->
    	</case>

    	<!– add endpoints as needed –>
    	<default>
        	<log level = "custom">
        	 	<property name="value" value="default operation is executed"/>
            </log>
        	<!-- logic if it satisfies this condition ie if the request is for the default request uri -->
	</switch>
</sequence>

Routing to different backends

Resource-based routing

You can route to different backends based on the resource which the APIs is invoked with. The logic being applied is similar to the Filtering based on a series of conditions.

In this example we set backend endpoints based on the resource of the API invocation. Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API. The steps are explained within the comments.

<sequence name="dynamic_ep" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
    <!-- The property which is retrieved as get-property('To')" stores the request URI for the API. Based on this value we will determine the endpoint which the request needs to be routed to.-->
	<switch source="get-property('To')">
    	<case regex=".*/countries/.*">
           <!-- We are then assigning the endpoint which we need to route to in a property named service_ep in this step -->
        	<property name="service_ep" value="https//first.backend.url"/>
    	</case>
    	<case regex=".*/regions/.*">
        	<property name="service_ep" value="https://something.different.url"/>
    	</case>
    	<!– add endpoints as needed –>
    	<default>
        	<property name="service_ep" value="http://some.default.url"/>
        	<!–default endpoint if required. However there should be a matching resource–>
    	</default>
	</switch>
          <!-- Next we need to store this endpoint in a header named To as shown below -->
	<header name="To" expression="get-property('service_ep')"></header>
	<property expression="get-property('service_ep')" name="ENDPOINT_ADDRESS"></property>
	<!–Please note that "ENDPOINT_ADDRESS" (additional) property is defined here in order to populate
    destination address for statistics (API Usage by Destination). –>
</sequence>

When using this sequence you need to provide the endpoint type in the Implement section as the Dynamic Endpoint, before uploading this sequence into your In Flow under mediation extensions.

Header-based routing

You can route you API to different endpoints based on an incoming header. 

This example shows how to create a single API and call multiple endpoints based on a version header passed in the request. You do not need to create an API for each backend endpoint version. You can easily use a custom sequence for the API to route to the required destination. The sample sequence is given below. Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.

<sequence xmlns="http://ws.apache.org/ns/synapse" name="VersionManagerSequence">
<!-- Property name is the parameter name that we added as a parameter when defining the endpoint url -->
<!-- Property expression is how we will be retrieving the version passed as a header, i defined the header as Version when invoking using curl-->
<property name="uri.var.version" expression="get-property('transport','Version')"/>
<!-- Here we are checking if a header named as Version is available or not.-->
	<filter source="boolean(get-property('uri.var.version'))" regex="false">
		<then>
		<!-- If no header mentioned as version is passed we will assign the version as our default version for the endpoint. So in the value you need to specify 	your default version of the endpoint -->
		<property name="uri.var.version" value="customerservice-default-version"/>
		<then>
		<else/>
	</filter>
</sequence>

When specifying the endpoint for your API you need to provide is as mentioned below. So that the version which is passed through the header will be read inside the custom sequence and the backend endpoint will be populated accordingly.

http://backend_service/1.0.0/customerservice

When you invoke this API then you will be using a format similar to the cURL command given below. The request will be made to the specific version of the endpoint you pass as a header in your API call.

curl -k -v -X GET --header "Accept: application/json" --header "Version: customerservice-1.1.0" --header "Authorization: Bearer access_token" "https://gateway.api.cloud.wso2.com/t/tenant/customer/1.0/customerservice/customers/123"

Alternate Method

You can do the same using a dynamic sequence as well. For that you will need to make the below changes to the sequence explained in Resource-based routing. However all the versions needs to be defined and handled separately whereas the above sequence will dynamically populate any version which you pass in the header.

 Expand to see the sample sequence...
<sequence name="dynamic_ep" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
    <!-- The property which is retrieved as get-property('To')" stores the request URI for the API. Based on this value we will determine the endpoint which the request needs to be routed to.-->
	<switch source="get-property('transport','Version')">
    	<case regex="1.0.0.*">
           <!-- We are then assigning the endpoint which we need to route to in a property named service_ep in this step -->
        	<property name="service_ep" value="https//first.backend.url/1.0.0/customers/>
    	</case>
    	<case regex="2.0.0">
        	<property name="service_ep" value="https//first.backend.url/2.0.0/customers/"/>
    	</case>
    	<!– add endpoints as needed –>
    	<default>
        	<property name="service_ep" value="https//first.backend.url/1.0.0/customers/"/>
        	<!–default endpoint if required. However there should be a matching resource–>
    	</default>
	</switch>
    <!-- Next we need to store this endpoint in a header named To as shown below -->
	<header name="To" expression="get-property('service_ep')"></header>
	<property expression="get-property('service_ep')" name="ENDPOINT_ADDRESS"></property>
	<!–Please note that "ENDPOINT_ADDRESS" (additional) property is defined here in order to populate
    destination address for statistics (API Usage by Destination). –>
</sequence>



Working with properties

The Property Mediator has no direct impact on the message, but rather on the message context flowing through Synapse.

Syntax
<property name="string" [action=set|remove] [type="string"] (value="literal" | expression="xpath") [scope=default|transport|axis2|axis2-client] [pattern="regex" [group="integer"]]>
    <xml-element/>?
</property>

Setting properties within your custom mediation 

For a list of the types of properties which you are able to work with, see Properties Reference. All properties which need to be set follow the same basic syntax. The following are some examples of setting properties.

Setting a content type
Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="property_sequence"> 
	<property name="ContentType" value="text/xml" scope="axis2"/>                   
</sequence>
Setting a message type
Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="property_sequence"> 
	<property name="messageType" value="text/xml" scope="axis2"/>                   
</sequence>
Preserve SOAP headers
Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="property_sequence"> 
	<property name="preserveProcessedHeaders" value="true" scope="default"/>
</sequence>
Make POST requests without a payload
Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="no_body_for_post_sequence"> 
	<property name="NO_ENTITY_BODY" action="remove" scope="axis2"/>
</sequence>
Get HTTP status code
Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="status_code_property_sequence"> 
	<property name="HTTP_SC" value="500" scope="axis2"/>
</sequence>

Retrieving information about an API call 

Following are some properties which are available to retrieve information regarding an API.


Property name

Description

API_NAME

The name of the API. e.g., MyAPI

AM_KEY_TYPE

The type of the oauth key used for invoking the API. e.g., Production/Sandbox

SYNAPSE_REST_API_VERSION

Retrieves the version of the API. E.g., 1.0.0.

REST_SUB_REQUEST_PATH

Retrieves the sub request with path and query parameters. e.g.,"/CheckPhoneNumber?PhoneNumber=1234567&LicenseKey=0".

REST_API_CONTEXT or api.ut.context

Retrieves the context of the API in the form /t/tenantDomain/context/version for an API. e.g., "/t/tenant/new/1.0.0".

REST_FULL_REQUEST_PATH

Retrieves the entire request path. e.g., "/t/tenant/new/1.0.0/CheckPhoneNumber?PhoneNumber=1234567&LicenseKey=0".

SYNAPSE_REST_API_VERSION_STRATEGY

For example, "context".

TRANSPORT_IN_NAME

Retrieves the transport. (e.g., "https")

SYNAPSE_REST_API

Retrieves the name of the API. (e.g., "admin-AT-tenant.com--NewAPI:v1.0.0")

api.ut.HTTP_METHOD

The HTTP method which was used for the invocation. (e.g., GET/POST)

api.ut.application.name

The name of the OAuth2 application used for the invocation. (e.g., DefaultApplication)

api.ut.apiPublisher

The name of the person who published the API.  (e.g., clouduser@gmail.com@wso2cloud)

api.ut.userId

The user who invoked the API. (e.g., subuser@gmail.com@wso2cloud)


You can use these properties inside the in sequence of the API to log details. The following sample sequence is used to log the API name of the invoked API. Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.


Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="api_info_sequence"> 
	<log level="custom">  
		<property name="ApiName" scope="transport" expression="$ctx:API_NAME"/>
	</log>  
</sequence>

Reading path and query parameters inside the sequence

You can read your input parameters to your API using custom sequences.

Difference between the path and query parameter

Path parameters are the parameters which are provided inline in the request URL. Query parameters are passed after a “?” character and concatenated with an “&” operand.


Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="api_info_sequence"> 
	<log level="custom">  
		<!-- Retrieving the path parameter-->
		<property name="countryCode" scope="transport" expression="uri.var.code"/>    
		<!-- Retrieving the query parameter-->
		<property name="id" scope="transport" expression="query.param.id"/>                           
	</log>  
</sequence>

Moving query parameters to the REST path

Your API backend often does not match the desired frontend representation. For example, it might have extra parameters (such as API keys) that you do not want to expose and have some query parameters that you now want to just include in the REST path. You might want to do a transformation like shown in the diagram below. To do this, you need to retrieve the parameter useful-param from the end user and then add it to the URL.

For a similar usecase, see this blog post.

In this example, the original request which we make through our WSO2 gateway with be in the following format. 

https://gateway.api.cloud.wso2.com/t/wso2cloud/resource?useful-param=foo&aux=bar

When we map it to the backend which we have defined the request will be sent as follows.

https://new.api/foo?useful-param=foo&aux=bar

Since what we really need to send to the backend is https://new.api/foo and we need to remove of the query parameters which are appended with the request URI defined in the original request. We need to add a sequence which drop the original request parameters from the request.The REST_URI_POSTFIX property removes the parameters in the request. Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.

Syntax
<sequence xmlns="http://ws.apache.org/ns/synapse" name="drop_uri_sequence" >
	<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
</sequence>

Disable chunking

Some back-end servers do not accept chunked content. You need to disable chunking of the API requests made through the API Cloud. Save the following code as an xml file. For instructions on adding this custom sequence to your API, see Add a Custom Sequence to your API.

Syntax
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="disable-chunking">
	<property name="DISABLE_CHUNKING" value="true" scope="axis2" />
</sequence>

Debugging your requests

When making API requests it may be required to log certain attributes in the API request to verify the correctness of the requests. You can do this using the log mediator. This will log specific information which is requested through the sequence to the live log viewer.

There are four main levels of logging in the API Cloud

  • Full: If this is selected, all the standard headers logged at the Simple level as well as the full payload of the message will be logged. This log level causes the message content to be parsed and hence incurs a performance overhead.

  • Simple: If this is selected, the standard headers (i.e. To, From, WSAction, SOAPAction, ReplyTo, and MessageID) will be logged.

  • Headers: If this is selected, all the SOAP header blocks are logged.

  • Custom: If this is selected, only the properties added to the Log mediator configuration will be logged.

Syntax of log mediator
<log [level="string"] [separator="string"]>
   <property name="string" (value="literal" | expression="[XPath|json-eval(JSON Path)]")/>*
</log>

See Retrieving information about an API call for a list of details regarding API calls.

Debugging requests
Syntax
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="debug_in_flow" xmlns="http://ws.apache.org/ns/synapse">
     <!-- All the standard headers as well as the full payload of the message will be logged -->
 	 <log level="full" />
	 <log level="custom">
                       <!-- Logs the host -->
	 	<property name="Host" expression="get-property('transport', 'Host')"/>
                        <!-- Logs the context of the API -->
		<property name="Context" expression="get-property('To')"/>
                       <!-- Logs the HTTP Method used for invoking the API -->
		<property name="HTTP_METHOD" expression="get-property('axis2', 'HTTP_METHOD')"/>
                        <!-- logs the request URI-->
		<property name="Resource" expression="$axis2:REST_URL_POSTFIX"/>
                       <!-- Logs the origin of the request -->
		<property name="Origin" expression="get-property('transport', 'Origin')"/>
                        <!-- Logs the content type of the request -->
		<property name="Content-Type" expression="get-property('transport', 'Content-Type')"/>
	 </log>

</sequence>

The following sequence is available in WSO2 API Cloud by default. See Add a Custom Sequence to your API for instructions on adding this to your API.

  • In Flow - debug_in_flow
Debugging responses
Syntax
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="debug_out_flow" xmlns="http://ws.apache.org/ns/synapse">
    <!-- All the standard headers as well as the full payload of the message will be logged -->
	<log level="full" />
	<log level="custom">
		<property name="EndPoint" expression="get-property('ENDPOINT_PREFIX')"/>
		<property name="Content-Type" expression="get-property('transport', 'Content-Type')"/>
	</log>
</sequence>


The following sequence is available in WSO2 API Cloud by default. See Add a Custom Sequence to your API for instructions on adding this to your API.

  • Out Flow - debug_out_flow

Service Chaining with API Cloud

If you need to invoke multiple other endpoints in order to get data to make the actual request of the API then you need to use a concept of service chaining. This sequence can be used if you need the response of calling one service to be used as the input to call the other service.

In this example we get the country name from the user and pass is to a backend to display the statistics for that country. The statistics backend requires the country ID to be passed and not the country name. The country ID which maps to the input country name should be obtained from an intermediate service.


 Expand to see the description of the numbered steps in the diagram.
  • Request a-1 -> The API Consumer application makes a request to the API with a parameter names country.
  • Request b -> The request is received at the in flow custom mediation of the API and then it makes a call to an intermediate service to get the country details. Within the sequence a request is made to the endpoint passing the country name which we received as the input. http://countries.com/getCountry/us
  • Response b -> It returns the country details of the above endpoint back into the in flow custom mediation sequence along with the country id which is needed for the actual backend call.
  • Request a-2 -> This takes the response b as the input parameter to the actual backend which returns the stats of the country. This response is sent back to the user.

If you have a similar service chaining requirement with WSO2 API Cloud please contact our support team on cloud@wso2.com for us to provide you the steps and assist you with this usecase.

Other custom mediation scenarios

If the custom mediation flow you are looking for is not listed in the examples above, contact us via support or by simply send an email to cloud@wso2.com with your use case.

Viewing sequences uploaded to APIs

To view the sequences which have already been uploaded to the APIs or to view the default sequences available in API Cloud follow the instructions given here.

  • No labels