Monday, October 12, 2015

[WSO2 API manager] Converting API GET requests to send a POST request to the backend

Some users of WSO2 API manager has this requirement of changing the HTTP method of the incoming request and send it to the backend with a different HTTP method. As an example some users want to change a GET request coming to the API extract some values from the query parameters and send it as a POST request after generating a payload which is required to the backend. Let's see how we can achieve this with WSO2 API Manager, for this blog post I'm using the latest API manager 1.9.1 version but this would work for earlier versions as well.

First of all let's get the requirement clarified first. 

I have a JAXRS service hosted in WSO2 Appserver which I want to expose through API Manager. In my service I have to send a POST request to the URL,

http://localhost:9763/jaxrs_basic/services/customers/customerservice
with a xml payload similar to below to create a new customer in the system.

<Customer>
   <name>Jack</name>
</Customer>


My real requirement is to expose this POST operation through an API such that, when the client sends a GET request to the API with name as a query parameter, it will generate the necessary payload and send it as a POST request to the back end URL above.

So Let's see how to do it.

First of all you need to create an API in APIManager publisher app and publish it. Make sure you add a resource similar to /sample/{name} with a uri-template in the API allowing GET method. And after that go to API Store log in and subscribe to the API you created. If you need help in this initial steps refer the API manager documentation [1] for further instructions.

Now, we have done the initial part, we have an API created with a GET resource. Let's see what are the modifications that we need to do for this API to convert this GET request to a POST request to be sent to the back end.

Find the API configuration xml file for your newly created API in <APIM_HOME>/repository/deployment/server/synapse-configs/default/api/ directory, and open it using a text editor.

Find the resource definition similar to below.

<resource methods="GET" uri-template="/sample/{name}" faultSequence="fault">

Now let's change few things inside the <inSequence> of this resource definition, and let me explain why we are changing them in that manner.

<property name="HTTP_METHOD" value="POST" scope="axis2" type="STRING"/>

Add the above to change the HTTP method of the outbound request to POST method.

<property name="messageType" value="text/xml" scope="axis2"/>
This will set the message type of the outbound payload to text/xml content type.

    <payloadFactory media-type="xml">
                  <format>
                      <Customer xmlns="">
                        <name>$1</name>
                      </Customer>
                  </format>
                  <args>
                    <arg expression="get-property('uri.var.name')"/>
                  </args>
    </payloadFactory>
Then you need to create the xml payload you need with the provided customer name input, that was passed as a query parameter in the GET request. You can use the payloadFactory mediator similar to above configuration to build the xml payload.

<property name="REST_URL_POSTFIX" value="" scope="axis2"/>
Finally you need to add this property in order to prevent the resource path that you send to the API GET resource being appended to the service endpoint URL. Note the empty value set in this property.

Ok that's it!!! Now it would change your API request like below to send to the backend service.

Request to API:

GET : http://hostname:port/apicontext/1.0.0/sample/john 


Request sent to the backend service :

POST : http://localhost:9763/jaxrs_basic/services/customers/customerservice
<Customer>
   <name>john</name>
</Customer>



The full synapse configuration for the GET resource is below.


<resource methods="GET" uri-template="/sample/{name}" faultSequence="fault">
      <inSequence>
         <filter source="$ctx:AM_KEY_TYPE" regex="PRODUCTION">
            <then>
               <property name="api.ut.backendRequestTime"
                         expression="get-property('SYSTEM_TIME')"/>
               <property name="HTTP_METHOD" value="POST" scope="axis2" type="STRING"/>
               <property name="messageType" value="text/xml" scope="axis2"/>
               <payloadFactory media-type="xml">
                  <format>
                      <Customer xmlns="">
                        <name>$1</name>
                      </Customer>
                  </format>
                  <args>
                    <arg expression="get-property('uri.var.name')"/>
                  </args>
               </payloadFactory>
               <property name="REST_URL_POSTFIX" value="" scope="axis2"/>
               <send>
                  <endpoint name="admin--JAXRSbasic_APIproductionEndpoint_0">
                     <http uri-template="http://localhost:9763/jaxrs_basic/services/customers/customerservice"/>
                  </endpoint>
               </send>
            </then>
            <else>
               <sequence key="_sandbox_key_error_"/>
            </else>
         </filter>
      </inSequence>
      <outSequence>
         <class name="org.wso2.carbon.apimgt.usage.publisher.APIMgtResponseHandler"/>
         <send/>
      </outSequence>
   </resource>


References

[1] https://docs.wso2.com/display/AM191/Quick+Start+Guide#QuickStartGuide-CreatinganAPIfromscratch

6 comments:

  1. Hi Nirodha, i have an issue about convert GET method to POST request to Backend. I have follow ur instructions, and it works perfectly. But it needs change directly on
    /repository/deployment/server/synapse-configs/default/api/
    My Question is how to solve it using sequence which will be defined on WSO2 Publisher(Implement InFlow) instead change directly on path above. Really appreciate for ur response. Thanks

    ReplyDelete
  2. • Nice and good article. It is very useful for me to learn and understand easily. Thanks for sharing your valuable information and time. Please keep updatingAzure Online Training hyderabad

    ReplyDelete
  3. Nice and good article. It is very useful for me to learn and understand easily. Thanks for sharing your valuable information and time.

    Digital Marketing Training in Chennai

    Digital Marketing Course in Chennai

    ReplyDelete