You're viewing Apigee Edge documentation.
Go to the
Apigee X documentation. info
Conditional statements are a common control structure in all programming languages. Like a programming language, API proxy configuration supports conditional statements for Flows, Policies, Steps, and RouteRules. By defining conditional statements, you define dynamic behavior for your API. This dynamic behavior lets you do things like converting XML into JSON only for mobile devices, or routing to a backend URL based on the content type or HTTP verb of the request message.
This topic shows you how to use conditions to dynamically apply API management features at runtime, without writing any code.
Configure conditional statements
Conditional behavior is implemented in API proxies by using a combination of conditions and variables. A conditional statement is created using a Condition element. The following is an empty condition:
<Condition></Condition>
To create a conditional statement, you add a conditional operator and a variable to create the following structure:
<Condition>{variable.name}{operator}{"value"}</Condition>
Supported conditional operators include =
(equals), !=
(not equal),
and >
(greater than). For readability, you can also write the conditionals as
text: equals
, notequals
, greaterthan
.
When working with URI paths you can use ~/
or MatchesPath
. You can
also match JavaRegex regular expressions with the ~~ operator.
Conditions are used to define API proxy conditional flows to backend API resources, described in Create conditional flows to backend API resources. For a complete list of conditionals, see Conditions reference.
Variables
Conditions do their work by evaluating the values of variables. A variable is a property of an HTTP transaction executed by an API proxy, or a property of an API proxy configuration itself. Whenever an API proxy gets a request from an app, Apigee Edge populates a long list of variables that are associated with things like system time, the app's network information, HTTP headers on messages, the API proxy configuration, policy executions and so on. This creates a rich context that you can use to set up conditional statements.
Variables always use a dotted notation. For example, HTTP headers on the request message are
available as variables called request.header.{header_name}
. So to evaluate the
Content-type header, you could use the variable request.header.Content-type
. For
example request.header.Content-type = "application/json"
indicates that the content
type of the request should be JSON.
Imagine that you need to create a conditional statement that will cause a policy to be
enforced only when a request message is a GET. To create a condition that evaluates the HTTP verb
of a request, you create the conditional statement below. The variable in this condition is
request.verb
. The value of the variable is GET
. The operator is
=
.
<Condition>request.verb = "GET"</Condition>
<Condition>request.verb equals "GET"</Condition>
Edge uses such a statement to evaluate conditions. The example above evaluates to true if the HTTP verb associated with the request is GET. If the HTTP verb associated with the request is POST, then the statement evaluates to false.
To enable dynamic behavior, you can attach Conditions to Flows, Steps, and RouteRules.
When you attach a condition to a Flow, you create a 'conditional Flow'. Conditional Flows execute only when the condition evaluates to true. You can attach as many Policies as you want to a conditional Flow. A conditional Flow enables you to craft highly specialized processing rules for request or response messages that meet certain criteria.
For example, to create a Flow that executes only when the request verb is a GET:
<Flows> <Flow name="ExecuteForGETs"> <Condition>request.verb="GET"</Condition> </Flow> </Flows>
To create one Flow for GETs and another for POSTs:
<Flows> <Flow name="ExecuteForGETs"> <Condition>request.verb="GET"</Condition> </Flow> <Flow name="ExecuteForPOSTs"> <Condition>request.verb="POST"</Condition> </Flow> </Flows>
As shown in the example below, you can apply the condition to the Policy Step itself. The following Condition causes the VerifyApiKey Policy to be enforced only if a request message is a POST.
<PreFlow name="PreFlow"> <Request> <Step> <Condition>request.verb equals "POST"</Condition> <Name>VerifyApiKey</Name> </Step> </Request> </PreFlow>
Once you have defined such conditional Flows, you can attach Policies to them, enabling an API proxy to enforce one set of policies for GET requests, and another set of policies for POST requests.
For comprehensive reference information, see the following resources:
Example 1
The following example shows a single conditional flow named Convert-for-devices
,
configured in the ProxyEndpoint response flow. Add the Condition as an element to the entity to
which the condition applies. In this example, the condition is a component of the flow.
Therefore, the flow will execute whenever the statement evaluates to true.
<Flows> <Flow name="Convert-for-devices"> <Condition>(request.header.User-Agent = "Mozilla")</Condition> <Response> <Step><Name>ConvertToJSON</Name></Step> </Response> </Flow> </Flows>
For each request received from an app, Edge stores the values of all HTTP headers present as
variables. If the request contains an HTTP header called User-Agent
, that header and
its value are stored as a variable called request.header.User-Agent
.
Given the ProxyEndpoint configuration above, Edge checks the value of the
request.header.User-Agent
variable to see whether the condition evaluates to
true.
If the condition does evaluate to true, that is, the value of the variable
request.header.User-Agent
equals Mozilla
, then the conditional Flow
executes and the XMLtoJSON policy called ConvertToJSON
is enforced. If not, the Flow
is not executed, and the XML response is returned unmodified (in XML format) to the requesting
app.
Example 2
Let's use a specific example in which you need to transform response message from XML to JSON—but only for mobile devices. First, create the policy that will convert the XML-formatted response from the Weather API into JSON:
<XMLToJSON name="ConvertToJSON"> <Options> </Options> <OutputVariable>response</OutputVariable> <Source>response</Source> </XMLToJSON>
The policy configuration above tells the API proxy to take the response message, perform a
conversion from XML to JSON with default settings, and then write the result to the new response
message. (If you are converting a request message from XML to JSON, you simply set both of
these values to request
.)
Since you want to convert responses from XML to JSON, you need to configure a conditional response Flow to perform the conversion. For example, to convert all responses from XML to JSON before they are returned to the client app, configure the following ProxyEndpoint response Flow.
<Flows> <Flow name="Convert-for-devices"> <Response> <Step><Name>ConvertToJSON</Name></Step> </Response> </Flow> </Flows>
When you invoke the API using the standard request, the response is formatted in JSON.
However, your goal is to only convert Weather reports into JSON when the requesting client is a mobile device. To enable such dynamic behavior, you must add a conditional statement to the Flow.
Test the conditional flow
In this sample request, the HTTP User-Agent
header is set to
Mozilla
, causing the conditional statement to evaluate to true and the conditional
flow Convert-for-devices
to execute.
$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282
or, to pretty print where Python is available:
$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282 | python -mjson.tool
Sample Response:
. . . "yweather_forecast": [ { "code": "11", "date": "12 Dec 2012", "day": "Wed", "high": "55", "low": "36", "text": "Showers" }, { "code": "32", "date": "13 Dec 2012", "day": "Thu", "high": "56", "low": "38", "text": "Sunny" } ] } . . .
A request submitted without the User-Agent
header, or with a different value than
Mozilla
, will result in an XML-formatted response.
$ curl http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282
The unmodified XML response is returned.
Sample Response:
<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />
Pattern matching
This section describes how to use pattern matching with conditions in an Apigee flow.
Operators
This section describes how to use the following pattern matching operators in conditional statements:
- Matches operator: Simple pattern matching
- JavaRegex operator: Finer control over matching
- MatchesPath operator: Path fragment matching
Matches
Let's look at the "Matches" or "~" conditional operator first. These two operators are the same -- the English version, "Matches", is considered to be a more readable option.
Summary: The "Matches" operator gives you two possibilities. Either match the string literally, or do a wildcard match with "*". As you might expect, the wildcard matches zero or more characters. Let's see how this works.
The following XML shows a Step condition. It executes the SomePolicy policy when the condition
evaluates to true. In this example, we test the variable proxy.pathsuffix
, a
built-in variable in Edge that stores the path suffix of the request. Note, however, you can test
the value of any flow variable that contains a string. So, in this case, if the base path of the
incoming request is /animals
, and the request is /animals/cat
, then the
path suffix is the literal string "/cat
".
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix Matches "/cat")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Question: What proxy path suffix will cause SomePolicy to execute? There's only one possibility.
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes, because the proxy path suffix matches "/cat
"
exactly. It will not execute if the suffix is /bat
or /dog
or
"/
" or anything else.
Now, consider this conditional statement where we use the wildcard character
"*
":
<Condition>(proxy.pathsuffix Matches "/*at")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes, because the wildcard matches any character, and
"/cat
" is a match.
API Call:
GET http://artomatic-test.apigee.net/matchtest/bat
Does the policy execute? Yes, because the wildcard matches any character, "/bat"
is a match.
API Call:
GET http://artomatic-test.apigee.net/matchtest/owl
Does the policy execute? Certainly not -- although the wildcard matches the "o
",
the letters "wl
" are not matched.
Now, lets move the wildcard to the end of the suffix:
<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes, because the wildcard matches zero or more of any characters.
API Call:
GET http://artomatic-test.apigee.net/matchtest/bat
Does the policy execute? No, "/bat
" is not a match.
API call:
GET http://artomatic-test.apigee.net/matchtest/cat123
Does the policy execute? Yes, the wildcard matches zero or more of any characters, therefore
"123
" produces a match.
API call:
GET http://artomatic-test.apigee.net/matchtest/cat/bird/mouse
Does the policy execute? Yes, because the wildcard matches zero or more of any characters, so
"/bird/mouse
" produces a match. Note how an expression like this can get you into
trouble because it matches everything after the literal characters!
Question: Is the Matches operator case sensitive?
Yes. Assume you have a condition like this:
<Condition>(proxy.pathsuffix Matches "/*At")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? No, the wildcard matches any letter (regardless of case), but the lowercase "a" does not match "A".
API call:
GET http://artomatic-test.apigee.net/matchtest/bAt
Does the policy execute? Yes, the case matches.
Question: How do I escape characters with the Matches operator?
Use the percent "%" character to escape reserved characters. For example:
<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? No, the Matches operator is looking for the literal string "c*at".
API call:
GET http://artomatic-test.apigee.net/matchtest/c*at
Question:Does the policy execute?
Yes, this path, although a bit unusual, matches.
JavaRegex
As you can see, the "Matches" operator is great for simple situations. But you can use another operator, the "JavaRegex" or "~~" operator. These two are the same operator, except JavaRegex is considered to be more readable. It's called JavaRegex because it allows regular expression pattern matching, and Edge follows the same rules as the classes in the java.util.regex package in the Java language. The way the JavaRegex operator works is very different from the Matches operator, so it's important not to confuse the two!
Summary: The "JavaRegex" operator lets you use regular expression syntax in conditional statements.
The following code shows a Step condition. It executes the SomePolicy policy if the condition
evaluates to true. In this example, we test the variable proxy.pathsuffix
, a built-in
variable in Edge that stores the path suffix of the request. If the base path of the
incoming request is /animals
, and the request is /animals/cat
, then the
path suffix is the literal string "/cat
".
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Question: What proxy path suffix will cause SomePolicy to execute? Just like with the Matches operator, there's only one possibility in this case.
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes, because the proxy path suffix matches "/cat
"
exactly. It will not execute if the suffix is /bat
or /dog
or anything
else.
Now, let's create a regular expression using "*" quantifier. This quantifier matches zero or more of the preceding character.
<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? No! The "*" quantifier matches zero or more of the
preceding character, which is a "c
".
API Call:
GET http://artomatic-test.apigee.net/matchtest/ccccct
Does the policy execute? Yes, because the wildcard matches zero or more of the preceding character.
Next, we use the "?
" quantifier, which matches the preceding character once, or not
at all.
<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes. The "?
" quantifier matches zero or one occurrence of
the preceding character, which is an "a
".
API Call:
GET http://artomatic-test.apigee.net/matchtest/ct
Does the policy execute? Yes. The "?
" quantifier matches one or
none of the preceding character. In this case, there is no "a" character, so the
condition evaluates to true.
API Call:
GET http://artomatic-test.apigee.net/matchtest/caat
Does the policy execute? No. The "?" quantifier matches one of the preceding
character, which is an "a
".
Next, we use the "[abc]
" or "grouping" style of regex expression. It matches the
characters "a
" or "b
" or "c
".
<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes. We're using regular expressions here, and the
"[cbr]
" expression matches a "c", "b", OR "r". These calls are also matches:
GET http://artomatic-test.apigee.net/matchtest/bat
GET http://artomatic-test.apigee.net/matchtest/rat
But this is not a match:
GET http://artomatic-test.apigee.net/matchtest/mat
Question: Is the JavaRegex operator case sensitive?
Yes. Assume you have a condition like this:
<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>
API call:
GET http://artomatic-test.apigee.net/matchtest/cat
Does the policy execute? Yes, the regex matches zero or one of the preceding character, which is "a".
API call:
GET http://artomatic-test.apigee.net/matchtest/cAt
Question: Does the policy execute?
No, because the capital "A" does not match lowercase "a".
MatchesPath
The MatchesPath
operator can also be specified like this "~/". It looks a little bit like the
Matches
(~) and the JavaRegex (~~) operators. But MatchesPath is entirely different.
Just remember that this operator looks at a path as a series of parts. Therefore, if the path
is: /animals/cats/wild
, you can think of the path as consisting of the parts
"/animals
", "/cats
", and "/wild
".
The MatchesPath
operator lets you use two wildcard notations: a single asterisk (*) and a
double asterisk (**). The single asterisk matches one path element. The double asterisk matches
one or many path elements.
Let's look at an example. In this example, we test the variable proxy.pathsuffix
,
a built-in variable in Edge that stores the path suffix of the request. Note, however, you can
test the value of any flow variable that contains a string.
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Question: What proxy path suffix will cause SomePolicy to execute?
API call:
GET http://artomatic-test.apigee.net/matchtest/animals
Question: Does the policy execute?
No, because condition requires another path element after
"/animals
", as specified by "/*
".
API call:
GET http://artomatic-test.apigee.net/matchtest/animals
/
Does the policy execute? Yes, the path does have another path element (the part after
"/animals/
"), but it's just empty.
API Call:
GET http://artomatic-test.apigee.net/matchtest/animals/cats
Does the policy execute? Yes, because the path clearly has an element ("/cats
")
that comes after "/animals
"
API Call:
GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild
Question: Does the policy execute?
No, because the single asterisk only matches one path element, and
this API has more than one element after "/animals
".
Now let's use the double asterisk:
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
Question: What proxy path suffix will cause SomePolicy to execute?
API call:
GET http://artomatic-test.apigee.net/matchtest/animals
Does the policy execute? No, because condition requires at least one following path element
specified by "/**
".
API call:
GET http://artomatic-test.apigee.net/matchtest/animals
/
Does the policy execute?
Yes, the path does have another path element (the part after
"/animals/
"), but it's just empty.
API Call:
GET http://artomatic-test.apigee.net/matchtest/animals/cats
Does the policy execute?
Yes, because the path has at least one element that comes after
"/animals
"
API Call:
GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild
Does the policy execute?
Yes, because the path has more than one element that comes after
"/animals
"
Mixing asterisks
You can use combinations of the single (*) and double (**) asterisk to further refine your path matching.
<PreFlow name="PreFlow"> <Request> <Step> <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
API call:
All of these API calls will produce a match:
GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild/
and
GET http://artomatic-test.apigee.net/matchtest/animals/dogs/wild/austrailian
and
GET
http://artomatic-test.apigee.net/matchtest/animals/birds/wild/american/finches
API resources
RESTful services are collections of API resources. An API resource is a URI path fragment that identifies some entity that developers can access by calling your API. For example, if your service provides weather reports and weather forecasts, your backend service might define two API resources:
- http://mygreatweatherforecast.com/reports
- http://mygreatweatherforecast.com/forecasts
When you create an API proxy (as shown in the Build your first API proxy), at a minimum you're creating an alias base URL that maps to your backend service. For example:
Backend base URL | New/equivalent API proxy URL |
---|---|
http://mygreatweatherforecast.com | http://{your_org}-{environment}.apigee.net/mygreatweatherforecast |
At this point you can make API calls to your backend using either base URL. But when you use the API proxy URL, things start to get interesting.
In addition to API analytics that Edge starts to collect when you use the API proxy, proxies also let you define conditional flows that map to the resources on your backend. In essence, "If a GET call comes in to the /reports resource, Edge should do something."
The following image shows the behavior difference between two URLs that ultimately access the same backend. One is the un-proxied resource URL, the other is an Edge API proxy with a conditional flow to the same backend resource. We'll describe conditional flows in more detail below.
How API proxies map to specific backend resources
With an API proxy URL mapped to the base URL of the backend service (when you create the
proxy), you can add conditional flows to specific resources, such as the /reports
and /forecasts
resources mentioned earlier.
Let's say you wanted to have Edge "do something" when calls come in to the
/reports
or /forecasts
resources. At this point you're not telling Edge
what to do, just that it should be listening for calls to those resources. You do this
with conditions. In your Edge API proxy, you can create conditional flows for
/reports
and /forecasts
. For conceptual purposes, the following API
proxy XML shows what those conditions might look like.
<Flows> <Flow name="reports"> <Description/> <Request/> <Response/> <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition> </Flow> <Flow name="forecasts"> <Description/> <Request/> <Response/> <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition> </Flow> </Flows>
Those conditions say, "When a GET request comes in with /reports
and
/forecasts
in the URL, Edge will do whatever you (the API developer) tell it to,
through the policies you attach to those flows.
Now here's an example of telling Edge what to do when a condition is met. In the following API
proxy XML, when a GET request is sent to
https://yourorg-test.apigee.net/mygreatweatherforecast/reports
, Edge executes
the "XML-to-JSON-1" policy in the response.
<Flows> <Flow name="reports"> <Description/> <Request/> <Response> <Step> <Name>XML-to-JSON-1</Name> </Step> </Response> <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition> </Flow>
In addition to those optional conditional flows, each API proxy also comes with two default
flows: a <PreFlow>
executed before your conditional flows, and a
<PostFlow>
executed after your conditional flows. Those are useful for
executing policies when any call is made to an API proxy. For example, if you want to
verify an app's API key with every call, regardless of the backend resource being accessed, you
could put a Verify API Key policy on the <PreFlow>
. For more on flows, see
Configuring flows.
Create conditional flows to backend resources
Defining conditional flows to backend resources in an API proxy is completely optional. However, those conditional flows give you the ability to apply fine-grained management and monitoring.
You will be able to:
- Apply management in way that reflects the semantics of your API model
- Apply policies and scripted behavior to individual resource paths (URIs)
- Collect fine-grained metrics for Analytics Services
For example, imagine that you need to apply different types of logic to your backend /developers to /apps resources.
To do so, you add two conditional flows in your API proxy: /developers
and
/apps
.
In the Develop view of the API proxy editor Navigator pane, click the + icon next to default in the Proxy Endpoints.
In the "New Conditional Flow" window, you'd enter the following key configurations:
- Flow name: Developers
- Condition Type: Path
- Path: /developers
The condition will be triggered (and policies will be executed) if a call is sent to the proxy with /developers at the end of the URI.
Now add a conditional flow for /apps, and assume you want the condition to be triggered on both the URI and the POST verb in a request. The configuration involves setting the following:
- Flow Name: Apps
- Condition Type: Path and Verb
- Path: /apps
- Verb: POST
The condition will be triggered (and policies will be executed) if a call is sent to the proxy with /apps at the end of the URI and a POST verb.
In the Navigator pane, you'll see new flows for Apps and Developers.
Select one of the flows to view the conditional flow configuration in the API proxy editor code view:
<Flow name="Apps"> <Description>Developer apps registered in Developer Services</Description> <Request/> <Response/> <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition> </Flow>
As you can see, API resources are simply conditional Flows that evaluate the URI path of the inbound request. (The proxy.pathsuffix variable identifies the URI of the request that follows the BasePath configured in the ProxyEndpoint configuration.)
Each API resource that you define is implemented by a conditional Flow in the API proxy. (See Configuring flows.)
Once you deploy the API proxy to the test environment, the following request:
http://{org_name}-test.apigee.net/{proxy_path}/apps
will cause the condition to evaluate to true, and this flow, along with any associated policies, will execute.
The following example condition uses a Java regular expression to recognize calls made to the
/apps
resource with or without a trailing forward slash (/apps
or
/apps/**
):
<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>
For more about this type of condition, see How to match regardless ... in the Apigee Community.
Modeling hierarchical URIs
In some cases, you will have hierarchical API resources. For example, the Developer Services API provides a method for listing all apps that belong to a developer. The URI path is:
/developers/{developer_email}/apps
You may have resources where a unique ID is generated for each entity in a collection, which is sometimes annotated as follows:
/genus/:id/species
This path applies equally to the following two URIs:
/genus/18904/species /genus/17908/species
To represent this structure in an API resource, you can use wildcards. For example:
/developers/*/apps
/developers/*example.com/apps
/genus/*/species
will resolve these hierarchical URIs as API resources appropriately.
In some cases, especially for deeply hierarchical APIs, you may simply want to resolve everything below a certain URI fragment. To do so, use a double asterisk wildcard in your resource definition. For example, if you define the following API resource:/developers/**
That API resource will resolve the following URI paths:
/developers/{developer_email}/apps /developers/{developer_email}/keys /developers/{developer_email}/apps/{app_id}/keys
Here's what the conditional flow condition would look like in the API proxy definition:
<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>
More examples
Condition attached to RouteRule
<RouteRule name="default"> <!--this routing executes if the header indicates that this is an XML call. If true, the call is routed to the endpoint XMLTargetEndpoint--> <Condition>request.header.content-type = "text/xml"</Condition> <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint> </RouteRule>
Condition attached to a policy
<Step> <!--the policy MaintenancePolicy only executes if the response status code is exactly 503--> <Condition>response.status.code = 503</Condition> <Name>MaintenancePolicy</Name> </Step>
Conditional Flow
<!-- this entire flow is executed only if the request verb is a GET--> <Flow name="GetRequests"> <Condition>request.verb="GET"</Condition> <Request> <Step> <!-- this policy only executes if request path includes a term like statues--> <Condition>request.path ~ "/statuses/**"</Condition> <Name>StatusesRequestPolicy</Name> </Step> </Request> <Response> <Step> <!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400--> <Condition>(response.status.code = 503) or (response.status.code = 400)</Condition> <Name>MaintenancePolicy</Name> </Step> </Response> </Flow>
Sample operators in conditions
Here are some examples of operators used to create conditions:
request.header.content-type = "text/xml"
request.header.content-length < 4096 && request.verb = "PUT"
response.status.code = 404 || response.status.code = 500
request.uri MatchesPath "/*/statuses/**"
request.queryparam.q0 NotEquals 10
A practical example: Ignore "/" at the end of a path
Edge developers commonly want to handle both of these path suffixes: "/cat
" and
"/cat/
". This is because some users or clients might call your API with the extra
slash on the end of the path, and you need to be able to handle that in your conditional
statements. This exact use case
has been discussed on the Apigee Community.
If you prefer, you can achieve this without using Regex like this:
<PreFlow name="PreFlow"> <Request> <Step> <Condition>((proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition> <Name>SomePolicy</Name> </Step> </Request> <Response/> </PreFlow>
This is a good option. It is clear and readable.
You can do the same thing with Regex, however, like this. The parentheses are used to group the regex part of the statement, but they are not required.
<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>
API Calls:
GET http://artomatic-test.apigee.net/matchtest/cat
or
GET http://artomatic-test.apigee.net/matchtest/cat
/
Does the policy execute? Yes. Note that in a regular expression, the "?
"
character means: match zero or one of the preceding character. Therefore, both
"/cat
" and "/cat/
" are matches.
API Call:
GET http://artomatic-test.apigee.net/matchtest/cat/spotted
Does the policy execute? No. The regular expression matches zero or only one occurrence of the preceding character, and nothing else is allowed.
Matching arbitrary strings with JavaRegex
In all of the examples in this topic, we show how to match one of the built-in flow variables: proxy.pathsuffix. It's good to know that you can do pattern matching on any arbitrary string or flow variable, whether or not it's a built-in flow variable like proxy.pathsuffix.
If for example you have a condition that tests an arbitrary string, perhaps a string returned in a backend payload, or a string returned from an authentication server lookup, you can use matching operators to test it. If you use JavaRegex, the regular expression will be compared against the entire subject string. If the subject is "abc" and the regular expression is "[a-z]", there is no match, because "[a-z]" matches exactly one alpha character. The expression "[a-z]+" works, as does "[a-z]*", and "[a-z]{3}.
Let's look at a concrete example. Suppose the authentication server returns a list of roles as a comma-delimted string: "editor, author, guest".
To test the presence of the editor role, this construction will not work, because "editor" is only part of the entire string.
<Condition>returned_roles ~~ "editor"</Condition>
However, this construction will work:
<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>
It works because it takes into account word breaks and any other parts of the string with the .* prefix and suffix.
In this example, you can also test for "editor" with the Matches operator:
<Condition>returned_roles ~~ "*editor*")</Condition>
However, in cases where you need more precision, JavaRegex is often a better choice.
Escaping double quotes in JavaRegex expressions
The Condition syntax requires a JavaRegex expression to be wrapped in double quotes; therefore, if you have a Regex expression that includes double quotes, you need an alternate way to match them. The answer is Unicode. For example, let's say you pass in a header that includes double quotes, like the following:-H 'content-type:multipart/related; type="application/xop+xml"'
request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"
\u0022
. For example,
the following expression is valid and produces the expected result:
request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"