API Validation on Target response flow before returning to client

I am looking to achieve and implement some validation via Apigee for my API proxy as per below:

I am working on an API proxy where some of the parameters on the request body payload ( for example: shopName) when sent from the client to the target server, I would like Apigee to perform some validation (whether the request has an exact match with the target response of that specific parameter) when the target server returns in the response before passing through to the client, as I have different conditions for raise fault or error message conditions based on

if request.data.shopName === target.response.shopName, return 200 OK else 404 Not found.

What would be the best approach to achieve this during the runtime without storing the request parameter to the KVM, app attributes for further validation? 

Solved Solved
0 3 347
1 ACCEPTED SOLUTION

I think I understand what you're asking. In the API Proxy, after receiving the response from the target, You want to compare a parameter from the original client request, to a parameter in the target response. No problem.

What is the format of the target response? Let's suppose it's JSON. And let's suppose you want to compare a queryparam from the request to a value in that json hash. Apigee makes available the queryparam for the inbound client request in a context variable named like request.queryparam.PARAMNAME . This context variable is available in the request flow, and also in the response flow. There's no need to store anything in the KVM or do anything in particular to keep that state around. Apigee does that for you. So, to check whether the inbound parameter matches something from the response, you want a step attached in the response flow, with a condition like this:

 

<Condition>request.queryparam.shopname = SOMETHING_FROM_THE_RESPONSE</Condition>

 

Or you could do the logical inverse of that condition, with a NOT operator:

 

<Condition>NOT(request.queryparam.shopname = SOMETHING_FROM_THE_RESPONSE)</Condition>

 

But what is SOMETHING_FROM_THE_RESPONSE ? Apigee inserts the entire target response body into a context variable called response.content. But it is just a string, and there is no automatic setting of specific context variables corresponding to the fields in JSON body. To get the SOMETHING_FROM_THE_RESPONSE, you can use the ExtractVariables step. It might look like this:

 

<ExtractVariables name='EV-Shopname-from-Response'>
  <Source>response</Source>
  <VariablePrefix>extracted</VariablePrefix>
  <JSONPayload>
    <Variable name='shopname'>
       <JSONPath>$.shopName</JSONPath>
    </Variable>
  </JSONPayload>
</ExtractVariables>

 

If the format of the response is not JSON, maybe it's XML or something else, then you'd replace that ExtractVariables with a different ExtractVariables, or some other thing that parses the response and extracts the field of interest.

Attach that EV step somewhere in the Proxy Response flow. After that step executes, if there was a toplevel field named shopName in the JSON body, then you will have a variable named extracted.shopname in the message context. Which means you could do something like this in your flow:

 

<Response>
  <Step>
    <Name>EV-Shopname-from-Response</Name>
  </Step>
  <Step>
    <Name>RF-Not-Found</Name>
    <Condition>NOT(request.queryparam.shopname = extracted.shopname)</Condition>
  </Step>
   ...

 

You may not need a RaiseFault there... you could use AssignMessage and set the status to 404. The difference is that RaiseFault interrupts further normal step processing, while AssignMessage will not. Also you may want another step in there, Conditioned on a test like extracted.shopname = null , to check if no shopname was in the response at all.

So it should be pretty easy, if I'm understanding the question correctly.

But I have to say, this is a little unusual. Normally, the target server will return 404 when 404 is appropriate. It's odd for a proxy to receive a 200 from the target and then override it with 404 if something in the response doesn't look right. I guess it would make sense to do this if the interface for the target is not very sensible, or if you're transforming it in some way.

good luck.

View solution in original post

3 REPLIES 3

I think I understand what you're asking. In the API Proxy, after receiving the response from the target, You want to compare a parameter from the original client request, to a parameter in the target response. No problem.

What is the format of the target response? Let's suppose it's JSON. And let's suppose you want to compare a queryparam from the request to a value in that json hash. Apigee makes available the queryparam for the inbound client request in a context variable named like request.queryparam.PARAMNAME . This context variable is available in the request flow, and also in the response flow. There's no need to store anything in the KVM or do anything in particular to keep that state around. Apigee does that for you. So, to check whether the inbound parameter matches something from the response, you want a step attached in the response flow, with a condition like this:

 

<Condition>request.queryparam.shopname = SOMETHING_FROM_THE_RESPONSE</Condition>

 

Or you could do the logical inverse of that condition, with a NOT operator:

 

<Condition>NOT(request.queryparam.shopname = SOMETHING_FROM_THE_RESPONSE)</Condition>

 

But what is SOMETHING_FROM_THE_RESPONSE ? Apigee inserts the entire target response body into a context variable called response.content. But it is just a string, and there is no automatic setting of specific context variables corresponding to the fields in JSON body. To get the SOMETHING_FROM_THE_RESPONSE, you can use the ExtractVariables step. It might look like this:

 

<ExtractVariables name='EV-Shopname-from-Response'>
  <Source>response</Source>
  <VariablePrefix>extracted</VariablePrefix>
  <JSONPayload>
    <Variable name='shopname'>
       <JSONPath>$.shopName</JSONPath>
    </Variable>
  </JSONPayload>
</ExtractVariables>

 

If the format of the response is not JSON, maybe it's XML or something else, then you'd replace that ExtractVariables with a different ExtractVariables, or some other thing that parses the response and extracts the field of interest.

Attach that EV step somewhere in the Proxy Response flow. After that step executes, if there was a toplevel field named shopName in the JSON body, then you will have a variable named extracted.shopname in the message context. Which means you could do something like this in your flow:

 

<Response>
  <Step>
    <Name>EV-Shopname-from-Response</Name>
  </Step>
  <Step>
    <Name>RF-Not-Found</Name>
    <Condition>NOT(request.queryparam.shopname = extracted.shopname)</Condition>
  </Step>
   ...

 

You may not need a RaiseFault there... you could use AssignMessage and set the status to 404. The difference is that RaiseFault interrupts further normal step processing, while AssignMessage will not. Also you may want another step in there, Conditioned on a test like extracted.shopname = null , to check if no shopname was in the response at all.

So it should be pretty easy, if I'm understanding the question correctly.

But I have to say, this is a little unusual. Normally, the target server will return 404 when 404 is appropriate. It's odd for a proxy to receive a 200 from the target and then override it with 404 if something in the response doesn't look right. I guess it would make sense to do this if the interface for the target is not very sensible, or if you're transforming it in some way.

good luck.

@dchiesa1  Do you think that this scenario is not meant to be validated by Apigee, but rather be done at the microservice on the target end? as if we do this on Apigee, do you think its not serving gateway purpose but rather doing "business logic and validation" which might affect performance too?

In my opinion performance is not an issue of concern. 

Whether to put such validation in Apigee or not is a judgment call.  Some organizations have full control of the target systems, and just want Apigee to provide a centrally administered way to enforce OAuth tokens, perform rate limiting, collect analytics, and do security checks.  In that case, it would not be appropriate or desirable for Apigee to perform checking of payloads and manipulation of response status code .  The upstream service should do that.

Other organizations are dealing with a heterogeneous portfolio of target systems, and for some of them, update and change of those target systems is not practically possible. Maybe the target system is practically speaking, un-changeable, or is a system managed by a 3rd party (3rd party SaaS for example).  In that case, Apigee is a handy tool for performing checking or validation of payloads, or for  manipulating the response status code . 

As an architect, I would look to balance what is feasible, against the longer term cost of maintenance,  and the business value of getting things done quickly.  Performance in Apigee will not be a concern. 

Often the approach is: we'll use Apigee as the mediation layer for now, and then later (in 6 months, 8 months, whatever) when we have time to update the target system, we'll do that, and at the same time remove the mediation stuff (changing status code and so on) from the Apigee proxy.  (And in these cases, sometimes the plan for 6 or 8 months  down the road actually comes to fruition, and sometimes it doesn't! )

Bottom line: whether to use Apigee in this way is a judgment call for you and your organization.