Was this helpful?

Conditional statements are a common control structure in all programming languages. Like a programming language, API proxy configuration supports conditional statements for Flows, Policies, 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.

Configuring 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 use conditions to evaluate regular expressions by using the ~~ or JavaRegex conditional.

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, API Services 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 setup 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 variable value 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>
You could also use:
<Condition>request.verb equals "GET"</Condition>

API Services 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.

API Services automatically stores all HTTP headers and query parameters as variables that can be accessed using request.header. and request.queryparam. variable prefixes.

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 references, see:

Conditionally converting a payload from XML to JSON

Let's use a specific example in which you need to transform response message from XML to JSON 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.)

The XMLToJSON policy type defines a set of reasonable defaults, which means that you only need to add configuration elements to craft XML into specific JSON structures. For instruction, refer to Convert XML to JSON

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.

Configuring conditional behavior

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 = &quot;Mozilla&quot;)</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

For each request received from an app, API Services 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, API Services 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.

Testing 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" />

Sample conditions

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 is 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

Conditional Flow

<!-- this entire flow is executed only if the response verb is a GET-->
<Flow name="GetRequests">
  <Condition>response.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

Add new comment

Provide your email address if you wish to be contacted offline about your comment.
We will not display your email address as part of your comment.

We'd love your feedback and perspective! Please be as specific as possible.
Type the characters you see in this picture. (verify using audio)

Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.