Monday, August 8, 2016

How to validate JSON request pay load before passing to back end - WSO2 API Manager

Sometimes users need to validate request data before process them and forward to mediation flow. In this article i will discuss about how we can validate input request json message.

First you need to identify message you need to validate. In this sample i will use following JSON message.
'{"greet": {"name": "sanjeewa"}}'


Before any processing is happen i need to verify at least we have one single element with name because without name back end cannot process request further.
So in request name is mandatory parameter. Now lets write XSD to validate input request. With XSDs you cannot validate exact JSON messages but as you know inside synapse run time
all messages will converted to xml message and flow continue. So we can log incoming message and how it looks like during the mediation flow. Then we can write XSD validation logic as follows.
Please refer this article on how we can validate messages using xsd(http://soatutorials.blogspot.com/2014/08/validating-xml-messages-against-more.html).
To validate my request i created following XSD.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"

xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://www.wso2.org/types"
attributeFormDefault="qualified" elementFormDefault="unqualified">
<xs:element name="jsonObject">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="greet">
    <xs:complexType>
      <xs:sequence>
       <xs:element minOccurs="1" name="name" >
        <xs:simpleType>
         <xs:restriction base="xs:string">
             <xs:minLength value="1" />
         </xs:restriction>
        </xs:simpleType>
       </xs:element>
     </xs:sequence>
    </xs:complexType>
   </xs:element>
  </xs:sequence>
 </xs:complexType>
</xs:element>
</xs:schema>


Then we need to upload this XSD to registry. So we can use this during the message mediation flow. So i will go to registry browser and add it to this(/_system/config/schema.xsd) location.

Now i need to implement validate sequence which actually validate message. For that i created following sequence and engage it to mediation flow of API.
Please refer below sequence. There i created error payload and send error message if validation failed. Else message will continue to mediation flow. As you can see here i have referred previously created XSD to validate message.

<sequence xmlns="http://ws.apache.org/ns/synapse" name="WSO2AM--Ext--In--validateJSON"

<validate>
    <schema key="conf:/schema.xsd"/>
         <on-fail>
     <payloadFactory media-type="xml">
        <format>
            <am:fault xmlns:am="http://wso2.org/apimanager">
                <am:code>555</am:code>
                <am:type>Status report</am:type>
                <am:message>Runtime Error</am:message>
                <am:description>Request format is incorrect</am:description>
            </am:fault>
        </format>
    </payloadFactory>
    <property name="RESPONSE" value="true"/>
    <header name="To" action="remove"/>
    <property name="HTTP_SC" value="555" scope="axis2"/>
    <property name="NO_ENTITY_BODY" scope="axis2" action="remove"/>
    <property name="ContentType" scope="axis2" action="remove"/>
    <property name="Authorization" scope="transport" action="remove"/>
    <property name="Access-Control-Allow-Origin" value="*" scope="transport"/>
    <property name="Host" scope="transport" action="remove"/>
    <property name="Accept" scope="transport" action="remove"/>
    <property name="X-JWT-Assertion" scope="transport" action="remove"/>
    <property name="messageType" value="application/json" scope="axis2"/>
    <send/>
    </on-fail>
</validate>
</sequence>



Then i will add this sequence to mediation flow while creating API as follows.


Then i will save and publish this API and invoke it as follows.
First i will invoke API with wrong JSON payload and i will type name as name1(which is wrong according to XSD). Then users should get error message as we defined in validate sequence.

curl -v -k -X POST --header 'Content-Type: application/json'
 --header 'Accept: application/xml' --header 'Authorization: Bearer a5e48a2ed76ba7437b452d7687a20a6b'
 -d '{"greet": {"name1": "sanjeewa"}}' 'http://172.17.0.1:8280/validateAPI/1.0.0/'
*   Trying 172.17.0.1...
* Connected to 172.17.0.1 (172.17.0.1) port 8280 (#0)
> POST /validateAPI/1.0.0/ HTTP/1.1
> Host: 172.17.0.1:8280
> User-Agent: curl/7.43.0
> Content-Type: application/json
> Accept: application/xml
> Authorization: Bearer a5e48a2ed76ba7437b452d7687a20a6b
> Content-Length: 32
>
* upload completely sent off: 32 out of 32 bytes
< HTTP/1.1 555
< Access-Control-Allow-Origin: *
< Content-Type: application/json; charset=UTF-8
< Date: Mon, 08 Aug 2016 09:16:46 GMT
< Transfer-Encoding: chunked
<
* Connection #0 to host 172.17.0.1 left intact
{"fault":{"code":555,"type":"Status report","message":"Runtime Error","description":"Request format is incorrect"}}


So you can see error message as as we defined in validate sequence.
Now i will send correct JSON message as follows.

curl -v -k -X POST --header 'Content-Type: application/json' 
--header 'Accept: application/xml' 
--header 'Authorization: Bearer a5e48a2ed76ba7437b452d7687a20a6b' 
-d '{"greet": {"name": "sanjeewa"}}' 
'http://172.17.0.1:8280/validateAPI/1.0.0/'

*   Trying 172.17.0.1...
* Connected to 172.17.0.1 (172.17.0.1) port 8280 (#0)
> POST /validateAPI/1.0.0/ HTTP/1.1
> Host: 172.17.0.1:8280
> User-Agent: curl/7.43.0
> Content-Type: application/json
> Accept: application/xml
> Authorization: Bearer a5e48a2ed76ba7437b452d7687a20a6b
> Content-Length: 31
>
* upload completely sent off: 31 out of 31 bytes
< HTTP/1.1 200 Success
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: DELETE,POST,PATCH,PUT,GET
< Access-Control-Allow-Headers: authorization,Access-Control-Allow-Origin,Content-Type
< Content-Type: text/html
< Location: https://www.test.com/
< Date: Mon, 08 Aug 2016 09:17:23 GMT
< Transfer-Encoding: chunked
<
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.9.15</center>
</body>
</html>


As you can see here it will validate properly and send to nginx back end and it returns 302 as response.



1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete