Was this helpful?

You have now learned how to create and deploy an API proxy that acts as a passive 'passthrough' proxy. API proxy development gets interesting when you change the behavior of an API by applying policies.

The Apigee API Platform defines a set of out-of-the-box policies. A policy is a configuration file that encapsulates an atomic unit of common management functionality. The purpose of policies is to provide advanced management capabilities without requiring developers to write and maintain code. Policies are designed to be easily understood and reusable.

Policies can be combined into policy compositions to enable sophisticated, yet easily managed and maintained, API behavior. Policies and compositions can also be augmented with custom scripts and code, enabling developers to delegate mundane tasks to policies, while focusing creative development effort on implementing custom logic, in turn using the API platform as a cloud deployment environment in which to expose, manage, and scale custom API behavior.

A policy is an XML-formatted configuration file. A policy's structure, required and optional elements, is defined by an XML schema. Each policy type has an associated XML schema that specifies the necessary configuration. If you are proficient with XML tools, it is worthwhile to familiarize yourself with the policy schemas in the API Platform samples on Github.

A complete list of out-of-the-box policies is documented in the API Platform Policy Reference.

For documentation specific to the Quota policy used in this topic, please refer to Rate limit API traffic using Quota.

Creating a policy

This topic uses the Quota policy type as an example of how to create, configure, attach, deploy, and test policies.

Quota policies are very common. Quotas provide control over how often a client app is permitted to invoke an API over a given time interval. In the example below, a Quota policy is configured to limit apps to 1 request per minute. (While this may not be realistic, it does provide a simple way to see the effects of a policy.)

Policy files are stored as XML files under /apiproxy/policies directory.

For example, a policy of type Quota called "QuotaPolicy" could be created as a file called QuotaPolicy.xml with the following content:

<Quota enabled="true" continueOnError="false"
async="false" name="QuotaPolicy">
    <Allow count="1"/>
    <Interval>1</Interval>
    <TimeUnit>minute</TimeUnit>
</Quota>

All policies have some settings that are specific to the policy type, and some settings that are generic across all policies.

All policies define the following attributes:

  • enabled: Indicates whether the policy is turned "on" or "off". Policies can be enabled/disabled at runtime by changing this setting. A policy that has enabled set to false is not enforced.
  • continueOnError: Defines whether the pipeline should continue processing the message if the policy fails. When enforcing quota policies, errors likely indicate that the quota has been exceeded, and, therefore, this attribute should be set to false.
  • async: If set to true the processing pipeline will continue processing subsequent policy steps before the current step completes. Asynchronous setting is useful, for example, when using policies to call out to external APIs or services as part of a flow.
  • name: The name that you give to this policy. This name is unique to this policy instance, and it is used to attach the policy to the flow as a processing step.

In the example above, the elements Allow, Interval, and TimeUnit are specific to the quota policy. These elements provide settings that the API Platform enforces on behalf of an API. Other policy types define their own settings.

Attaching a policy to a ProxyEndpoint or TargetEndpoint Flow

Policies in the /policies directory are available to be executed in the processing pipeline of a ProxyEndpoint or a TargetEndpoint. You can think of the /policies directory as a repository for instances of policies. The policies in the repository have no effect until they are attached as a processing 'Step' in the API proxy Flow.

The choice of attachment point is critical. If you attach the Quota policy to a response Flow, for example, the Quota would be enforced after the request message was sent to the backend service. That would defeat the purpose of applying a Quota policy! Therefore, we need to attach the Quota policy as a processing Step on the request Flow.

The format of a policy attachment is:

<Step>
    <Name>{policy_name}</Name>
</Step>

For example:

<Step>
    <Name>QuotaPolicy</Name>
</Step>

A policy is attached to a Flow by adding the Step configuration to the appropriate request or response flow in a ProxyEndpoint or TargetEndpoint. For example, a Quota must be enforced before any additional processing occurs. Therefore, a Quota policy should be attached to the ProxyEndpoint request 'PreFlow'. A PreFlow is an important construct. A PreFlow always executes, even if other Flows are configured to execute dynamically. (Dynamic execution is an advanced topic that you will cover in a later topic.)

The following example demonstrates a simple ProxyEndpoint configuration has no policy attachments. It simply defines the HTTPConnections and a RouteRule.

<ProxyEndpoint name="default">
    <HTTPProxyConnection>
        <BasePath>/weather</BasePath>
        <VirtualHost>default</VirtualHost>
    </HTTPProxyConnection>
  <RouteRule name="default">
     <TargetEndpoint>default</TargetEndpoint>
  </RouteRule>
</ProxyEndpoint>

You must modify this configuration so that the ProxyEndpoint enforces a Quota policy (as a processing Step) before the API proxy performs any other processing. If a developer has exceeded a Quota, you don't want to waste any computational resources on additional requests.

To enforce this configuration, you attach a processing Step to the request PreFlow as follows:

<ProxyEndpoint name="default">
  <PreFlow>
    <Request>
      <Step><Name>QuotaPolicy</Name></Step>
    </Request>
  </PreFlow>
  <HTTPProxyConnection> 
    <BasePath>/weather</BasePath> 
    <VirtualHost>default</VirtualHost> 
  </HTTPProxyConnection> 
  <RouteRule name="default"> 
    <TargetEndpoint>default</TargetEndpoint> 
  </RouteRule> 
</ProxyEndpoint>

Note that the rest of the ProxyEndpoint configuration remains the same. The only change is that you added the PreFlow, Request, and Step elements. In the ProxyEndpoint configuration above, the Quota policy executes when the ProxyEndpoint receives a request from a client app, and before any additional processing takes place.

Importing and deploying changes

Whenever you modify API proxy, you must import and deploy. Policy changes do not take effect until the modified configuration files have been imported and deployed.

To deploy your changes, run the Python deploy tool, substituting your username and password for myname:mypass and your Apigee organization for myorg.

$ python tools/deploy.py -n weatherapi -u myname:mypass -o myorg -e test -p / -d simpleProxy

You should see the following result:

Writing ./simpleProxy/apiproxy/weatherapi.xml to apiproxy/weatherapi.xml
Writing ./simpleProxy/apiproxy/policies/QuotaPolicy.xml to apiproxy/policies/QuotaPolicy.xml
Writing ./simpleProxy/apiproxy/proxies/default.xml to apiproxy/proxies/default.xml
Writing ./simpleProxy/apiproxy/targets/default.xml to apiproxy/targets/default.xml
Imported new proxy version 2
Undeploying revision 1 in same environment and path:
Environment: test
  Revision: 2 BasePath = /
  State: deployed

Note that the deploy tool deploys a new revision number, and provides a notice indicating that the previous revision has been undeployed. If necessary, the revision mechanism can be used to revert to the previous revision of the API proxy, thus rolling back any changes. The Apigee deploy tool always increments the revision number of an API proxy on import.

You can also use the shell scripts provided with the API Platform samples on GitHub. Those scripts simply wrap the Python deploy, and therefore provide an example of how you might start scripting your deployment procedures. By scripting deployment procedures, you gain the benefit of consistency, repeatability, and so on.

Verifying policy enforcement

To verify that a policy is enforced properly, the API must be invoked by an HTTP client. To verify this Quota configuration, submit multiple request to the API, exceeding the quota limit that you set in the quota policy. (The URI path, configured as the base path setting in the ProxyEndpoint, in the request below is /weather).

http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

After you submit more than 1 request within a minute:

{"fault":{"faultstring":"policies.ratelimit.QuotaViolation","detail":{"errorcode":"policies.ratelimit.QuotaViolation"}}}

Now that you understand how to create and attach a simple Quota policy, you can begin working locally with all of the policies that are provided by Apigee.

Configuring conditional policy enforcement

A powerful feature of the API Platform is conditional policy enforcement.

Conditional statements can be added to policy attachments. For example, to add a conditional statement that enforces a quota policy only for XML messages:

<Step>
  <Condition>request.header.content-type = "text/xml"</Condition>
    <Name>QuotaPolicy</Name>
</Step>

The configuration above enforces the Quota policy as a processing Step only if the conditional statement evaluates to true. In other words, the Quota is enforced on inbound request messages where the HTTP content-type header is set to text/xml.

The API Platform evaluates the HTTP content-type header in the request message from the client, and checks to see whether that value equals text/xml. If the condition evaluates to true, the policy is enforced. If not, the policy is bypassed.

The API Platform automatically makes all HTTP headers and query parameters available as variables. For example, the following request message to an API:

$ curl http://apifactory-test.apigee.net/weather/forecastrss?w=12797282&apikey=h789srfhuih -H "User-Agent:Mozilla/5.0"

Results in the following variables being set:

request.queryParam.w=12797282
request.queryParam.apikey=h789srfhuih
request.header.User-Agent=User-Agent:Mozilla/5.0

Conditions have two components, a variable and a conditional operator.

The configuration above uses a variable defined by Apigee: request.header.content-type. Many other variables are defined by the API Platform, providing a rich environment in which to implement dynamic, context-driven behavior. You can also define your own custom variables to support dynamic behavior specific to the content of the messages that your apps and API exchange.

For more, refer to the the list of Variables reference and Conditions Reference.

Post questions to the Apigee Developer Forum.

Back to API Platform Developer Guide.