APIGEE API Proxy - How do I prevent a request from hitting the target based on body content - apigee

I am trying to prevent requests that contain a json payload with a certain attribute value from hitting my target backend.
For example:
{"status":"pending"}
If the status is "pending", I don't want it to hit my target backend until I see a status of "delivered".
What is the best way to do this?
I have a step in the proxy endpoint preflow that uses a javascript policy to identify the attribute and its value. Now that I know this, how can I prevent the request from hitting the target backend and instead just return a 200 ok to the requester?

As you have the JS to identify the attribute already, now have a policy "Raise-Fault-Attribute" in your preflow after your JS policy.
<Step>
<Condition>(Status is pending) or (Status is null)</Condition>
<Name>Raise-Fault-Attribute</Name>
</Step>
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RaiseFault async="false" continueOnError="false" enabled="true" name="Raise-Fault-Attribute">
<DisplayName>Raise Fault Attribute</DisplayName>
<Properties/>
<FaultResponse>
<Set>
<Headers/>
<Payload contentType="text/xml">
....
</Payload>
<StatusCode>500</StatusCode>
<ReasonPhrase>Server Error</ReasonPhrase>
</Set>
</FaultResponse>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>
`
Hope this helps...

Related

APIM 4.1 Publish and Try out

im new with APIM 4.1 product. im trying for try_out my project on APIM. but when i put my request and send request request to backend. i got error details :
CORS
Network Failure
URL scheme must be "http" or "https" for CORS request.
when i try with integration studio 8.1 with micro service server 4.1 hit local endpoint API i make. i always get http 400 bad status
my project code for this :
`<?xml version="1.0" encoding="UTF-8"?>
<api context="/sample2" name="Sample2" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<log description="Request send to endpoint" level="custom">
<property name="Request Log" value="** Send Request To Endpoint **"/>
</log>
<send>
<endpoint key="Test1"/>
</send>
</inSequence>
<outSequence>
<log description="Response back from endpoint" level="custom">
<property name="Response Log" value="** Response Back From Endpoint **"/>
</log>
<send/>
</outSequence>
<faultSequence/>
</resource>
</api>`
<?xml version="1.0" encoding="UTF-8"?>
<endpoint name="Test1" xmlns="http://ws.apache.org/ns/synapse">
<http method="post" uri-template="http://apiceupfdev01.ptap.co.id:31065">
<suspendOnFailure>
<initialDuration>-1</initialDuration>
<progressionFactor>1.0</progressionFactor>
</suspendOnFailure>
<markForSuspension>
<retriesBeforeSuspension>0</retriesBeforeSuspension>
</markForSuspension>
</http>
</endpoint>
maybe anyone can helping me with this case.
i expecting get response from backend endpoint i hit
I tried your project on a 4.1.0 pack with an HTTP URL for the endpoint.It worked with a 200 for API invocation call.
If you are getting CORS-related errors, did you try to create the API from the publisher and disable CORS from the runtime configurations[1]? (It is disabled by default for the new APIs that are created from the publisher portal)
[1] - https://apim.docs.wso2.com/en/latest/design/advanced-topics/enabling-cors-for-apis/#enabling-cors-globally

How to post parameter with special symbol like "\/" or "|" in https://apigee.com GET api request?

We are trying to use an external SOAP service in our mobile app. We are converting that SOAP service into a GET method REST api using https://apigee.com. But that REST api , is changing our parameter value (which contain some special character like / | and all), when hitting actual SOAP api. How can we stop this encoding/decoding part in Apigee? is their any other free service available there for same purpose ?
REST API GET Request. So you will be sending request parameters in the URL as query parameters. Use the below flow
Use Extract Variables policy to extract query parameter variables
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="true" enabled="true" name="getqueryparams">
<DisplayName>getqueryparams</DisplayName>
<QueryParam name="param1">
<Pattern ignoreCase="true">{param1}</Pattern>
</QueryParam>
<QueryParam name="param2">
<Pattern ignoreCase="true">{param2}</Pattern>
</QueryParam>
<QueryParam name="param3">
<Pattern ignoreCase="true">{param3}</Pattern>
</QueryParam>
<Source>request</Source>
<VariablePrefix>getqueryparams</VariablePrefix>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</ExtractVariables>
Use Service callout policy to create and send SOAP POST Request
<ServiceCallout async="false" continueOnError="false" enabled="true" name="Service-Callout-1">
<DisplayName>Custom label used in UI</DisplayName>
<Request clearPayload="true" variable="myRequest">
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<Set>
<Headers>
<Header name="Content-Type">text/xml</Header>
<Header name="SOAPAction">http://www.webserviceX.NET/GetWeather</Header>
</Headers>
<Payload contentType="text/xml">
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetWeather xmlns="http://www.webserviceX.NET">
<CityName>{getqueryparams.param1}</CityName>
<CountryName>{getqueryparams.param2}</CountryName>
</GetWeather>
</soap:Body>
</soap:Envelope>
</Payload>
<Verb>POST</Verb>
</Set>
</Request>
<Response>response</Response>
<Timeout>60000</Timeout>
<HTTPTargetConnection>
<URL>http://www.webservicex.com/globalweather.asmx</URL>
</HTTPTargetConnection>
</ServiceCallout>
Use xml to json policy to convert the response xml to JSON in RESPONSE flow
Your service URL: http://superman-prod.apigee.net/service/getService?param1=abc/xyz&param2=one|two&param3=omgomgomg

How to use the same Flow for request and response for Apigee proxy?

For Apigee API proxy, I need to select a flow based on request parameter. But I also need to remove that parameter before sending the request to the target.
I tried doing this:
<Flow name="SpecialFlow">
<Condition>request.queryparam.specialKey != null</Condition>
<Request>
<Step>
<Name>removeSpecialKey</Name>
</Step>
</Request>
<Response>
<Step><Name>doSpecialStuff</Name></Step>
</Response>
</Flow>
However, since specialKey is removed, the response step doSpecialStuff never gets called. How do I make sure the same flow is used for both request and response in this case?
I remove the parameter like:
context.removeVariable('request.queryparam.specialKey');
Great question and a common scenario. In my proxies I use one of two strategies.
In the first I a saveVars policy right before I head to the target flow, typically as the last step in the preflow request. That policy looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="true" enabled="true" name="assignSaveMessage">
<DisplayName>assignSaveMessage</DisplayName>
<AssignVariable>
<Name>save.request.verb</Name>
<Ref>request.verb</Ref>
</AssignVariable>
<AssignVariable>
<Name>save.request.queryparam.content</Name>
<Ref>request.queryparam.content</Ref>
</AssignVariable>
<AssignVariable>
<Name>save.request.content</Name>
<Ref>request.content</Ref>
</AssignVariable>
<AssignVariable>
<Name>save.request.queryparam.propagation</Name>
<Ref>request.queryparam.propagation</Ref>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
I then execute a restoreVars policy in the first step of postFlow response. This way I can use those variables as conditions. Here is the restore policy:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="true" enabled="true" name="assignRestoreMessage">
<DisplayName>assignRestoreMessage</DisplayName>
<AssignVariable>
<Name>request.verb</Name>
<Ref>save.request.verb</Ref>
</AssignVariable>
<AssignVariable>
<Name>request.queryparam.content</Name>
<Ref>save.request.queryparam.content</Ref>
</AssignVariable>
<AssignVariable>
<Name>request.queryparam.propagation</Name>
<Ref>save.request.queryparam.propagation</Ref>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
In your case, you would "stash" your queryparam right before you remove it as a queryparam.
The second approach is to simply assign the request param into another variable, a custom labelled variable that can be accessed throughout the flow. The only concern with this approach is the source of these copied variables is not obvious later flows.

Service callout with dynamic host name

I have a proxy in Apigee that uses a service callout to another proxy in the same environment. I would like to set the URL host for the callout to match the host of the initial request.
For example, if a request is made in the dev environment to:
https://example-dev.apigee.com/awesome-proxy
I need to make a call to:
https://example-dev.apigee.com/support-proxy
In a test environment the first call is to:
https://example-test.apigee.com/awesome-proxy
The support call needs to go to:
https://example-test.apigee.com/support-proxy
Here is how I would like to define the service callout policy:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="serviceCallout">
<DisplayName>serviceCallout</DisplayName>
<FaultRules/>
<Properties/>
<Request clearPayload="true" variable="example.request">
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</Request>
<Response>example.response</Response>
<HTTPTargetConnection>
<Properties/>
<URL>{client.host}/support-proxy</URL>
</HTTPTargetConnection>
</ServiceCallout>
This will not save and complains about no protocol. The help indicates that this must be hard coded:
<HTTPTargetConnection>/<URL> element
The URL to the service being called. While the hostname portion of URL must be hard-coded, you can supply the remainder of the URL dynamically with a variable.
I found a variable to define the URL of a service callout:
servicecallout.{policy-name}.target.url
I attempted to use an assign message policy to dynamically set the variable, as follows:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="assignCalloutURL">
<DisplayName>assignCalloutURL</DisplayName>
<FaultRules/>
<Properties/>
<AssignVariable>
<Name>servicecallout.serviceCallout.target.url</Name>
<Value>{client.host}</Value>
<Ref/>
</AssignVariable>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
This sets the URL to the literal text {client.host}
I have used the assign message policy in a similar fashion for other purposes and it actually resolves the variable listed. I'm not sure what's happening here.
client.host is not the correct variable to use, it returns an IP address 192.168....
I tried a few other variables:
proxy.url returns a strange host, it looks like internal Apigee machine names with a port. The proxy.url host times out when hit directly.
I ended up using virtualhost.aliases and proxy.pathsuffix. Here is the full JavaScript that solved it:
var base = context.getVariable("proxy.basepath");
var aliases = context.getVariable("virtualhost.aliases");
var url = "https://" + aliases[0] + base + "/support-proxy";
context.setVariable("servicecallout.serviceCallout.target.url", url);
Modifying target URLs gets a little goofy when dealing with the linter that ensures URLs have valid values.
This will not save and complains about no protocol.
This is because you're missing the scheme (https:// or http://) before the URL (client.host doesn't include scheme).
This sets the URL to the literal text {client.host}
That bit's not working properly because you need to use the ref tag to retrieve the existing variable:
<AssignVariable>
<Name>servicecallout.serviceCallout.target.url</Name>
<Ref>client.host</Ref>
</AssignVariable>
Now, that might work for the service callout, but it's not probably not going to work for setting the target URL.
I've ended up creating JavaScript policies to handle target.url, since the AssignMessage has been problematic for me:
var scheme = context.getVariable("client.scheme");
var host = context.getVariable("client.host");
var pathsuffix = context.getVariable("proxy.pathsuffix");
var newUrl = scheme + host + pathsuffix;
context.setVariable("target.url", newUrl);
Take look at this - it worked for me.

How to set custom error message for Quota violation?

I tried multiple options of publishing custom error message for Quota violation. But I was not able to produce custom error message.
Please provide step by step process to generate custom error message. Thanks!
Create a Raise Fault Policy (but don't attach it to a flow):
<RaiseFault async="false" continueOnError="false" enabled="true" name="Fault-Bad-Quota">
<DisplayName>Fault-Bad-Quota</DisplayName>
<FaultRules/>
<Properties/>
<FaultResponse>
<Set>
<Headers/>
<Payload contentType="text/plain">My Custom Fault for {fault.name}</Payload>
<StatusCode>500</StatusCode>
<ReasonPhrase>Server Error</ReasonPhrase>
</Set>
</FaultResponse>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>
Add a Conditional Fault to your Proxy configuration
<FaultRules>
<FaultRule name="BadQuota">
<Step>
<Name>Fault-Bad-Quota</Name>
</Step>
<Condition>fault.name = "QuotaViolation"</Condition>
</FaultRule>
</FaultRules>
You can add a global fault policy to your proxy default.xml. If you're using the UI go to the word "default" right under your target.

Resources