Deny API call with same payload parameter value like in the previous call (within a minute)

Hi Community

We have an API that sends a JSON payload with 15 fields/parameters in the request body. "Proposal number" is one out of those parameters we pass in JSON with every API call. So we want to ensure, backend do not receive another API call having the same Proposal number within a minute (since we've observed this recurring scenario occurring only within a minute).

Proposal number can be stored in APIGEE Edge Cache/KVM for a minute, after which this value/entry can be invalidated/removed. With this Proposal number having stored for a minute or so, we want to reject/deny every other API call with the same Proposal number in their JSON payload.

How can we do this using APIGEE policies, JS/Python service call-out etc etc? Kindly help us with detail answer. Thanks!

APIGEE Edge version: 4.18.01

Regards

Sajan Mathew

Solved Solved
1 6 554
1 ACCEPTED SOLUTION

sidd-harth
Participant V

I guess we can make use of PopulateCache, LookupCache and Raise Fault.

First Use an Extract variable policy to get the proposalNumber.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Variables-1">
    <DisplayName>Extract Variables-1</DisplayName>
    <Properties/>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <JSONPayload>
        <Variable name="number">
            <JSONPath>$.number</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">request</Source>
    <VariablePrefix>apigee</VariablePrefix>
</ExtractVariables>

Use a Lookup Cache to get the Value from Cache,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="Lookup-Cache-1">
    <DisplayName>Lookup Cache-1</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="apigee.number"/>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <AssignTo>flowVar</AssignTo>
</LookupCache>

Use a PopulateCache to Cache the extracted prososalNumber(number in my example) with 60sec expiry time.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="Populate-Cache-1">
    <DisplayName>Populate Cache-1</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="apigee.number"/>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <ExpirySettings>
        <TimeoutInSec>60</TimeoutInSec>
    </ExpirySettings>
    <Source>apigee.number</Source>
</PopulateCache>

Use a Raise Fault to raise an error based on some Conditions.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RaiseFault async="false" continueOnError="false" enabled="true" name="Raise-Fault-1">
    <DisplayName>Raise Fault-1</DisplayName>
    <Properties/>
    <FaultResponse>
        <Set>
            <Headers/>
            <Payload contentType="text/plain"/>
            <StatusCode>500</StatusCode>
            <ReasonPhrase>Received Same Proposal Number in a Minute</ReasonPhrase>
        </Set>
    </FaultResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>

Conditions can be something like this,

	<Request>
            <Step>
                <Name>Extract-Variables-1</Name>
            </Step>
            <Step>
                <Name>Lookup-Cache-1</Name>
            </Step>
            <Step>
                <Name>Populate-Cache-1</Name>
                <Condition>flowVar != apigee.number</Condition>
            </Step>
            <Step>
                <Name>Raise-Fault-1</Name>
                <Condition>flowVar = apigee.number</Condition>
            </Step>
        </Request>

Use a payload like,

{"number":1}


When you make a call for the first time with a payload like {"number":1},

  • the number will be extracted
  • but the LookUpCache will not find any Cache for the extarctedNumber so the flow will continue and
  • execute the PopulateCache to store the extarctedNumber in cache for 60seconds and
  • the Raise Fault will be skipped.

When you make a call for the second time with same payload {"number":1} within a minute,

  • the number will be extracted,
  • LookupCache will get the cache and assign it to flowVar.
  • as the flowVar(number) from LookupCache is equal to extractedNumber,
    • the Populate Cache will be skipped
    • RaiseFault will be executed


Note -

I have not tried these steps, so not sure if it is going to work. Try it on a sample proxy and check.

I have not followed/used naming conventions so take care of them in your proxy.


View solution in original post

6 REPLIES 6

sidd-harth
Participant V

I guess we can make use of PopulateCache, LookupCache and Raise Fault.

First Use an Extract variable policy to get the proposalNumber.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Variables-1">
    <DisplayName>Extract Variables-1</DisplayName>
    <Properties/>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <JSONPayload>
        <Variable name="number">
            <JSONPath>$.number</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">request</Source>
    <VariablePrefix>apigee</VariablePrefix>
</ExtractVariables>

Use a Lookup Cache to get the Value from Cache,

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="Lookup-Cache-1">
    <DisplayName>Lookup Cache-1</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="apigee.number"/>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <AssignTo>flowVar</AssignTo>
</LookupCache>

Use a PopulateCache to Cache the extracted prososalNumber(number in my example) with 60sec expiry time.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="Populate-Cache-1">
    <DisplayName>Populate Cache-1</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="apigee.number"/>
    </CacheKey>
    <Scope>Exclusive</Scope>
    <ExpirySettings>
        <TimeoutInSec>60</TimeoutInSec>
    </ExpirySettings>
    <Source>apigee.number</Source>
</PopulateCache>

Use a Raise Fault to raise an error based on some Conditions.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RaiseFault async="false" continueOnError="false" enabled="true" name="Raise-Fault-1">
    <DisplayName>Raise Fault-1</DisplayName>
    <Properties/>
    <FaultResponse>
        <Set>
            <Headers/>
            <Payload contentType="text/plain"/>
            <StatusCode>500</StatusCode>
            <ReasonPhrase>Received Same Proposal Number in a Minute</ReasonPhrase>
        </Set>
    </FaultResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>

Conditions can be something like this,

	<Request>
            <Step>
                <Name>Extract-Variables-1</Name>
            </Step>
            <Step>
                <Name>Lookup-Cache-1</Name>
            </Step>
            <Step>
                <Name>Populate-Cache-1</Name>
                <Condition>flowVar != apigee.number</Condition>
            </Step>
            <Step>
                <Name>Raise-Fault-1</Name>
                <Condition>flowVar = apigee.number</Condition>
            </Step>
        </Request>

Use a payload like,

{"number":1}


When you make a call for the first time with a payload like {"number":1},

  • the number will be extracted
  • but the LookUpCache will not find any Cache for the extarctedNumber so the flow will continue and
  • execute the PopulateCache to store the extarctedNumber in cache for 60seconds and
  • the Raise Fault will be skipped.

When you make a call for the second time with same payload {"number":1} within a minute,

  • the number will be extracted,
  • LookupCache will get the cache and assign it to flowVar.
  • as the flowVar(number) from LookupCache is equal to extractedNumber,
    • the Populate Cache will be skipped
    • RaiseFault will be executed


Note -

I have not tried these steps, so not sure if it is going to work. Try it on a sample proxy and check.

I have not followed/used naming conventions so take care of them in your proxy.


Thanks Siddharth for the wonderful narration of the steps and logic. I will try this out over the weekend/next week and let you all know.

I have not tried these steps, so not sure if it is going to work.

It will work. Not sure about the exact syntax, but the pattern and the idea is correct.

Hi@Siddharth Barahalikar@Dino-at-Google

Cache Policies are not working as expected for my requirement, though I tried things from my end too. I am getting CacheHit = false, everytime I test. Please find the details below. Any suggestions would be more than welcome. Thanks!

  • Trace Fields:
Variables
apigee.metrics.policy.LC-ToFindExtractedParam.timeTaken
apigee.metrics.policy.PC-toStoreExtractedParam.timeTaken
flowVar
Number
lookupcache.LC-ToFindExtractedParam
Number
Request Content
Body{
"Number" : 9,
"First Name" : "Sajan",
"Last Name" : "Mathew"
}
{
"Number" : 9,
"First Name" : "Sajan",
"Last Name" : "Mathew"
lookupcache.LC-ToFindExtractedParam.assigntoflowVar
lookupcache.LC-ToFindExtractedParam.cachehitfalse
lookupcache.LC-ToFindExtractedParam.cachekeymathewsajan14-trial__prod____9
lookupcache.LC-ToFindExtractedParam.cachenamemathewsajan14-trial__prod
lookupcache.LC-ToFindExtractedParam.failedfalse
  • Extract Variable Policy (Working):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="EV-NumberParam">
    <DisplayName>EV-NumberParam</DisplayName>
    <Properties/>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <JSONPayload>
        <Variable name="Number">
            <JSONPath>$.Number</JSONPath>
        </Variable>
    </JSONPayload>
    <Source clearPayload="false">request</Source>
</ExtractVariables>
  • Lookup Cache (CacheHit = False always //doesn't seem to be working, though I tried many changes in this policy)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LookupCache async="false" continueOnError="false" enabled="true" name="LC-ToFindExtractedParam">
    <DisplayName>LC-ToFindExtractedParam</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="Number"/>
    </CacheKey>
    <Scope>Global</Scope>
    <AssignTo>flowVar</AssignTo>
</LookupCache>
  • Populate Cache Policy:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="PC-toStoreExtractedParam">
    <DisplayName>PC-toStoreExtractedParam</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="Number"/>
    </CacheKey>
    <Scope>Global</Scope>
    <ExpirySettings>
        <TimeoutInSec>60</TimeoutInSec>
    </ExpirySettings>
    <Source>flowVar</Source>
</PopulateCache>
  • Raise Fault Policy:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RaiseFault async="false" continueOnError="false" enabled="true" name="RF-ifSameExtractedParamFoundAgain">
    <DisplayName>RF-ifSameExtractedParamFoundAgain</DisplayName>
    <Properties/>
    <FaultResponse>
        <Set>
            <Headers/>
            <Payload contentType="application/json"/>
            <StatusCode>400</StatusCode>
            <ReasonPhrase>Proposal number repeat hit</ReasonPhrase>
        </Set>
    </FaultResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>
  • Proxy Flow:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>EV-NumberParam</Name>
            </Step>
            <Step>
                <Name>LC-ToFindExtractedParam</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <Flows>
        <Flow name="PopulateCache">
            <Request>
                <Step>
                    <Name>PC-toStoreExtractedParam</Name>
                    <Condition>Number != flowVar</Condition>
                </Step>
            </Request>
        </Flow>
        <Flow name="RaiseFault">
            <Request>
                <Step>
                    <Name>RF-ifSameExtractedParamFoundAgain</Name>
                    <Condition>Number = flowVar</Condition>
                </Step>
            </Request>
        </Flow>
    </Flows>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <HTTPProxyConnection>
        <BasePath>/blocksamerequest</BasePath>
        <Properties/>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

Well, I guess the issue is with your PopulateCache Policy, you defined <Source> as flowVar, whereas it should be Number in your case.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PopulateCache async="false" continueOnError="false" enabled="true" name="PC-toStoreExtractedParam">
    <DisplayName>PC-toStoreExtractedParam</DisplayName>
    <Properties/>
    <CacheKey>
        <Prefix/>
        <KeyFragment ref="Number"/>
    </CacheKey>
    <Scope>Global</Scope>
    <ExpirySettings>
        <TimeoutInSec>60</TimeoutInSec>
    </ExpirySettings>
    <Source>flowVar</Source> <!-- flowVar should be replaced with Number extracted using extract variable policy -->
</PopulateCache><br>

Since PopulateCache is not creating a cache the LookupCache is failing.

BTW, I would recommend using a VariablePrefix in extract variable policy, it helps in identifying and referencing variables in an efficient manner,

<VariablePrefix>apigee</VariablePrefix><br>

Thank you @Siddharth Barahalikar. Commendable..