Skip to main content

WSO2 API Manager- Extended Mediation Capabilities on APIs -Part1

After a while,thought to write a blog-post about how we can use extended mediation capabilities with the published APIs from WSO2 APIManager.

Requirement- A back-end  endpoint with returning xml content need to wrap with an API from WSO2 APIManager to give additional security,throttling and monitoring capabilities for it.

For this blog-post,as the back-end endpoint,I have used the sample JAX-RS based web-app which can be found from here,deployed in WSO2 AS 5.2.1.You can try downloading WSO2 AS 5.2.1 and try deploying this web-app as instructed in here.I have started AS with port offset 2.Thus the deployed jax-rs web-app url is http://localhost:9765/Order-1.0/
This jax-rs web app supports following HTTP verbs with the url-patterns;

POST  /submitOrder    Input & Output content-type : text/xml

Input Payload:


<Order>
<customerName>Jack</customerName>
<quantity>5</quantity>
<creditCardNumber>233</creditCardNumber>
<delivered>false</delivered>
</Order>

GET    /orderStatus     Output content-type : text/xml
GET    /cancelOrder    Output content-type : text/xml



Then download the latest WSO2 AM 1.7.0 binary pack from here. With AM 1.7.0 we have done a major re-design the APIPublisher UI,in which allowing users to get the experience of designing APIs addition to implement APIs and manage APIs as previous AM publisher  versions are only focus on implement and manage APIs.
Start AM server,log in to APIPublisher app and create an API with below details;For more information,refer the quick start guide,
In Design API view,enter below parameters.

  • Name -order
  • Context -order
  • Version-v1

  Under Resources section,define following three API resources.

  •   URL-Pattern - submitOrder
              HTTP Verb - POST
             
  •   URL-Pattern -cancelOrder/{id}
              HTTP Verb- GET

  •  URL-Pattern - orderStatus/{id}
             HTTP Verb- GET

  •  URL-Pattern - confirmCancelOrder/*
             HTTP Verb- GET

a.png

   4) Then save the design API view content.Then click on ‘Implement’ button.

   5) Enter  above deployed JAXRS web app url [http://localhost:9765/Order-1.0/] as the production endpoint value with setting endpoint type as ‘HTTP Endpoint’.

 6) Then save the details and next click on ‘manage’ button.
 7) Select ‘Tier Availability’ as ‘Unlimited’


8) Set the Authentication Type for all API resources as ‘Application &amp; Application User’

9) Click ‘save & publish’ option in it.

Once created the above API and publish the API,you'll see a xml configuration named as admin--Order_v1.xml has been created at {AM}/repository/deployment/server/synapse-configs/default/api location.

<?xml version="1.0" encoding="UTF-8"?><api xmlns="http://ws.apache.org/ns/synapse" name="admin--Order" context="/Order" version="1" version-type="url">
    <resource methods="POST" url-mapping="/submitOrder">
        <inSequence>
           <property name="POST_TO_URI" value="true" scope="axis2"/>
            <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                <then>
                   <send>
                        <endpoint name="admin--TTT_APIproductionEndpoint_0" >
                            <address uri="https://10.100.1.85:9463/services/orderSvc/" format="soap11">
                                <timeout>
                                    <duration>30000</duration>
                                    <responseAction>fault</responseAction>
                                </timeout>
                                <suspendOnFailure>
                                    <errorCodes>-1</errorCodes>
                                    <initialDuration>0</initialDuration>
                                    <progressionFactor>1.0</progressionFactor>
                                    <maximumDuration>0</maximumDuration>
                                </suspendOnFailure>
                                <markForSuspension>
                                    <errorCodes>-1</errorCodes>
                                </markForSuspension>
                            </address>
                        </endpoint>
                    </send>
                </then>
                <else>
                    <sequence key="_sandbox_key_error_"/>
                </else>
            </filter>
        </inSequence>
        <outSequence>
            <send/>
        </outSequence>
    </resource>
    <resource methods="GET" uri-template="/cancelOrder/{id}">
        <inSequence>
            <property name="POST_TO_URI" value="true" scope="axis2"/>
            <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                <then>
                 
                </then>
                <else>
                    <sequence key="_sandbox_key_error_"/>
                </else>
            </filter>
        </inSequence>
        <outSequence>
            <send/>
        </outSequence>
    </resource>
    <resource methods="GET" uri-template="/orderStatus/{id}">
        <inSequence>
            <property name="POST_TO_URI" value="true" scope="axis2"/>
            <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                <then>
                   <send>
                        <endpoint name="admin--TTT_APIproductionEndpoint_0" >
                            <address uri="https://10.100.1.85:9463/services/orderSvc/" format="soap11">
                                <timeout>
                                    <duration>30000</duration>
                                    <responseAction>fault</responseAction>
                                </timeout>
                                <suspendOnFailure>
                                    <errorCodes>-1</errorCodes>
                                    <initialDuration>0</initialDuration>
                                    <progressionFactor>1.0</progressionFactor>
                                    <maximumDuration>0</maximumDuration>
                                </suspendOnFailure>
                                <markForSuspension>
                                    <errorCodes>-1</errorCodes>
                                </markForSuspension>
                            </address>
                        </endpoint>
                    </send>
                </then>
                <else>
                    <sequence key="_sandbox_key_error_"/>
                </else>
            </filter>
        </inSequence>
        <outSequence>
            <send/>
        </outSequence>
    </resource>
    <handlers>      
        <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>        
        <handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
            <property name="id" value="A"/>
            <property name="policyKey" value="gov:/apimgt/applicationdata/tiers.xml"/>
        </handler>      
        <handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler">
            <property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
        </handler>
        <handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
    </handlers>
</api>

Once publish the API,browse APIStore and create a subscription for this API and generate a application token from APIstore. 

Now let's try to invoke /submitOrder method of API. 

A sample curl request would be as ;

curl -d @payload.xml -H "Authorization:Bearer xxxxx" -H "Content-Type:text/xml" http://localhost:8280/Order/1/submitOrder 

payload.xml content -

<Order> <customerName>Jack</customerName> <quantity>5</quantity> <creditCardNumber>233</creditCardNumber> <delivered>false</delivered> </Order>

You'll observe a response similar to below.

<Order> <creditCardNumber>233</creditCardNumber> <customerName>Jack</customerName> <date>06/24/2014 08:43:52</date> <delivered>false</delivered> <orderId>a4c1315d-8a07-4e80-85b1-3795ab47db7a</orderId> <quantity>5</quantity> </Order>

New Requirement 1

Now,let's say you want to make the above Order API as a json/REST API.Thus the input and output has to be in json format.For this,you have to change the Order API xml content.Since AM 1.7.0 doesn't provide mediation UI capabilities,you can try directly editing the deployed api xml file located at {AM}/repository/deployment/server/synapse-configs/default/api.

Replace json message formatter and message builder


Replace below message-formatter and builder to axis2.xml of {AM}/repository/conf/axis2/ location and restart AM server.


Message Formatter

<messageFormatter contentType="application/json" class="org.apache.synapse.commons.json.JsonFormatter"/>


Message Builder

<messageBuilder contentType="application/json"
                       class="org.apache.synapse.commons.json.JsonBuilder"/>

To set response to be json format in /submitOrder resource of Order API.
Set messageType and content-type as ‘application/json’ in out-sequence of /submitOrder resource.

<outSequence> <property name="messageType" value="application/json" scope="axis2"/> <property name="ContentType" value="application/json" scope="axis2"/> <send/> </outSequence>

To accept json formatted inputs for /submitOrder API resource
To pass the payload as json from client and then convert that payload from json to xml in APIManager side,we have added below payload factory inside ‘/submitOrder’ API resource.

<payloadFactory media-type="xml"> <format> <Order> <customerName>$1</customerName> <quantity>$2</quantity> <creditCardNumber>$3</creditCardNumber> <delivered>$4</delivered> </Order> </format> <args> <arg expression="$.Order.customerName" evaluator="json"></arg> <arg expression="$.Order.quantity" evaluator="json"></arg> <arg expression="$.Order.creditCardNumber" evaluator="json"></arg> <arg expression="$.Order.delivered" evaluator="json"></arg> </args> </payloadFactory>

The changed order API is as below.
<?xml version="1.0" encoding="UTF-8"?><api xmlns="http://ws.apache.org/ns/synapse" name="admin--Order" context="/Order" version="1" version-type="url">
    <resource methods="POST" url-mapping="/submitOrder">
        <inSequence> 
<payloadFactory media-type="xml">
           <format>
           <Order>
  <customerName>$1</customerName>
  <quantity>$2</quantity>
  <creditCardNumber>$3</creditCardNumber>
  <delivered>$4</delivered>
</Order>

           </format>
           <args>           
            <arg expression="$.Order.customerName" evaluator="json"></arg>
            <arg expression="$.Order.quantity" evaluator="json"></arg>
            <arg expression="$.Order.creditCardNumber" evaluator="json"></arg>
<arg expression="$.Order.delivered" evaluator="json"></arg>
           </args>
           </payloadFactory>
 
            <property name="POST_TO_URI" value="true" scope="axis2"/>
            <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                <then>
                   <send>
                        <endpoint name="admin--TTT_APIproductionEndpoint_0" >
                            <address uri="https://localhost:9463/services/orderSvc/" format="soap11">
                                <timeout>
                                    <duration>30000</duration>
                                    <responseAction>fault</responseAction>
                                </timeout>
                                <suspendOnFailure>
                                    <errorCodes>-1</errorCodes>
                                    <initialDuration>0</initialDuration>
                                    <progressionFactor>1.0</progressionFactor>
                                    <maximumDuration>0</maximumDuration>
                                </suspendOnFailure>
                                <markForSuspension>
                                    <errorCodes>-1</errorCodes>
                                </markForSuspension>
                            </address>
                        </endpoint>
                    </send>
                </then>
                <else>
                    <sequence key="_sandbox_key_error_"/>
                </else>
            </filter>
        </inSequence>
        <outSequence>
 <property name="messageType" value="application/json" scope="axis2"/>
 <property name="ContentType" value="application/json" scope="axis2"/>
            <send/>
        </outSequence>
    </resource>
    <resource methods="GET" uri-template="/cancelOrder/{id}">
        <inSequence>
            <property name="POST_TO_URI" value="true" scope="axis2"/>
            <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                <then>
                 <send>
                        <endpoint name="admin--TTT_APIproductionEndpoint_0" >
                            <address uri="https://localhost:9463/services/orderSvc/" format="soap11">
                                <timeout>
                                    <duration>30000</duration>
                                    <responseAction>fault</responseAction>
                                </timeout>
                                <suspendOnFailure>
                                    <errorCodes>-1</errorCodes>
                                    <initialDuration>0</initialDuration>
                                    <progressionFactor>1.0</progressionFactor>
                                    <maximumDuration>0</maximumDuration>
                                </suspendOnFailure>
                                <markForSuspension>
                                    <errorCodes>-1</errorCodes>
                                </markForSuspension>
                            </address>
                        </endpoint>
                    </send>  
                <else>
                    <sequence key="_sandbox_key_error_"/>
                </else>
            </filter>
        </inSequence>
        <outSequence> 
            <send/>
        </outSequence>
    </resource>
    <resource methods="GET" uri-template="/orderStatus/{id}">
        <inSequence>
            <property name="POST_TO_URI" value="true" scope="axis2"/>
            <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
                <then>
                   <send>
                        <endpoint name="admin--TTT_APIproductionEndpoint_0" >
                            <address uri="https://localhost:9463/services/orderSvc/" format="soap11">
                                <timeout>
                                    <duration>30000</duration>
                                    <responseAction>fault</responseAction>
                                </timeout>
                                <suspendOnFailure>
                                    <errorCodes>-1</errorCodes>
                                    <initialDuration>0</initialDuration>
                                    <progressionFactor>1.0</progressionFactor>
                                    <maximumDuration>0</maximumDuration>
                                </suspendOnFailure>
                                <markForSuspension>
                                    <errorCodes>-1</errorCodes>
                                </markForSuspension>
                            </address>
                        </endpoint>
                    </send>
                </then>
                <else>
                    <sequence key="_sandbox_key_error_"/>
                </else>
            </filter>
        </inSequence>
        <outSequence> 
            <send/>
        </outSequence>
    </resource>
    <handlers>        
        <handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>      
        <handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
            <property name="id" value="A"/>
            <property name="policyKey" value="gov:/apimgt/applicationdata/tiers.xml"/>
        </handler>        
        <handler class="org.wso2.carbon.apimgt.usage.publisher.APIMgtGoogleAnalyticsTrackingHandler">
            <property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
        </handler>
        <handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
    </handlers>
</api>

Now let's try to invoke /submitOrder method of API. A sample curl request would be as ; 
curl -d @payload.json "Authorization:Bearer xxxxx" -H "Content-Type:application/json"  http://localhost:8280/Order/1/submitOrder

payload.json content -
{"Order":{"customerName:"PP_88","quantity":"8" ,".creditCardNumber":"1234","delivered":"true"}}
Response would be as below.
{"Order":{"orderId:"a4c1315d-8a07-4e80-85b1-3795ab47db7a","date:"06/24/2014 08:43:52","customerName:"PP_88","quantity":"8" ,".creditCardNumber":"1234","delivered":"true"}}

Comments

Popular posts from this blog

Convert an InputStream to XML

For that we can use DocumentBuilder class in java. By using the method parse(InputStream) ; A new DOM Document object will return. InputStream input; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder parser = factory.newDocumentBuilder(); Document dc= parser.parse(input); In the above code segment,by using the created Document object,the corresponding XML file for the inputStream can be accessed. References: http://www.w3schools.com/dom/dom_intro.asp http:// download.oracle.com/javase/1.4.2/docs/api/javax/xml/parsers/DocumentBuilder.html

Concat two xml values with XSLT

The use-case described in this blog-post,is there's an WSO2 ESB node setup to proxy an incoming message to a particular back-end endpoint.  Before delivering the message to the back-end endpoint,from the ESB node itself,this incoming message need to processed and change its inside xml payload format. For eg: Below is the incoming message <?xml version="1.0" encoding="UTF-8"?> <CinemaHall name="liberty"> <OwnerData> <Name>John Smith</Name> <openedDate>12/12/80</openedDate> <quality>good</quality> </OwnerData> <CinemaHallData> <rows>100</rows> <seats> <seat>50</seat> <seat>60</seat> </seats> </CinemaHallData> </CinemaHall> This message need to be changed as  below; <?xml version="1.0" encoding="UTF-8"?> <CinemaHall name="liberty"...

Passing end-user details from client to real backend endpoint via JWT token

In real-world business system,WSO2 API Manager useful on exposing company APIs, in a secured and controlled manner with the features provided by APIManager as; OAuth support [To secure API invocations] Throttling support [To control API invocations] Monitoring support [To track API usage] More technically what happening is when a user sends a particular API request,it will goes to WSO2 APIManager node and from there,the request will route to the real implemented back-end endpoint of the particular API and get back the response and returned it to the API invoked user. There can be a use-case,that this back-end endpoint may expect the details of API invoked user as to pass those details to some internal company usage  as; Additional authentication/authorization Track usage data from an internal system. So how to support above requirement from WSO2 AM. There comes the use of JSON Web Token[JWT] implementation done inside WSO2 AM. JWT is a means of representing claims to...