Property Manager API v0 Rule Trees

A property’s main functionality is encapsulated in its set of rules. This section details how rules operate, and how to structure a rule tree from the root down. It shows how to inject variables within rules and modify their value at runtime. It also shows how to interpret contextual rule format JSON schemas that specify your product’s level of support for various behaviors and criteria.

The Default Rule

The JSON object for the API’s Rules interface features a top-level rules element that specifies a default rule object. As discussed in the Debugging section, responses may also include top-level warnings, errors, and other contextual members, hence the additional layer of data. (The examples that follow remove extraneous data members.)

{
    "rules": {
        "name": "default",
        "options": {
            "is_secure": false
        }
    }
}

The rule’s default name is more than simply a default; the top-level rule must be named that way.

The only nominally mandatory member when saving a rule is its name, so you don’t have to pass in the options object, which as shown above displays default behavior. The Create a New Edge Hostname operation shows to specify hostnames as secure. When the property’s is_secure is set to true, it means you want to apply a shared certificate for all hostnames, possibly supplementing hostname-specific certificates. With is_secure enabled within the rule tree, you may receive warnings about any non-secure hostnames to which the rule applies. Note that some rule behaviors may only be available when is_secure is true.

Behaviors

The default rule must feature a set of behaviors, which is represented as an array of objects. New properties come with different sets of default rules depending on the product, but this much simpler example features the two behaviors that are always necessary to activate your property. The origin behavior determines how the edge network interacts with your origin servers, and the cpCode behavior is required for billing and reporting on traffic.

{
    "rules": {
        "name": "default",
        "options": {
            "is_secure": false
        },
        "behaviors": [
            {
                "name": "origin",
                "options": {
                    "originType": "CUSTOMER",
                    "hostname": "example.com",
                    "forwardHostHeader": "REQUEST_HOST_HEADER",
                    "cacheKeyHostname": "ORIGIN_HOSTNAME",
                    "compress": true,
                    "tcipEnabled": false,
                    "httpPort": 80
                }
            },
            {
                "name": "cpCode",
                "options": {
                    "value": {
                        "id": 12345,
                        "name": "main site"
                    }
                }
            }
        ]
    }
}

While nominally optional, default rules typically also specify a caching behavior to position the content on the edge, and a report behavior to refine the information you receive in traffic reports.

Each behavior object is identified by a name field. It features a locked member explained below, and most require a nested options object. Some behaviors only feature an enabled option that toggles whether the behavior is activated, while others require more fields once they’re activated. The exact set of options you need to specify for each behavior often varies depending on what you are trying to do, and some options are required based on the value of others. The Behaviors Reference details the requirements for each option.

In the origin example above, the originType is set to CUSTOMER, in which case your own server is the origin and you need to identify it with the hostname field. If the originType were set to any other value, the hostname would be unnecessary and thus ignored. PAPI silently ignores any unexpected values, but it always warns you about any expected values that are missing. (For example, setting the originType to NET_STORAGE would require another netStorage option providing details about your NetStorage account.)

Criteria

Rules are more powerful when they respond to the client request’s different criteria. To do so, the rule needs to specify children containing an array of nested rule objects. Along with a descriptive name, child rules may contain an additional set of criteria objects that determine when its behaviors execute.

In this example, the child rule’s contentType criteria matches requests for common HTML, CSS, and JavaScript files, and applies the gzipResponse behavior to compress them.

{
    "rules": {
        "name": "default",
        "options": {
            "is_secure": false
        },
        "behaviors": [
            {
                "name": "origin",
                "options": {
                    "originType": "CUSTOMER",
                    "hostname": "example.com",
                    "forwardHostHeader": "REQUEST_HOST_HEADER",
                    "cacheKeyHostname": "ORIGIN_HOSTNAME",
                    "compress": true,
                    "tcipEnabled": false,
                    "httpPort": 80
                }
            },
            {
                "name": "cpCode",
                "options": {
                    "value": {
                        "id": 12345,
                        "name": "main site"
                    }
                }
            }
        ],
        "children": [
            {
                "name": "Compress Text Content",
                "criteria": [
                    {
                        "name": "contentType",
                        "options": {
                            "matchOperator": "IS_ONE_OF",
                            "values": [
                                "text/html*",
                                "text/css*",
                                "application/x-javascript*"
                            ],
                            "matchWildcard": true,
                            "matchCaseSensitive": false
                        }
                    }
                ],
                "behaviors": [
                    {
                        "name": "gzipResponse",
                        "options": { "behavior": "ALWAYS" }
                    }
                ]
            }
        ]
    }
}

Criteria are structured exactly the same as behavior objects, with a name string identifier and a nested options object. Most criteria options behave similarly. The values option usually specifies the set of strings you are trying to match. (Throughout PAPI, whenever a value is optionally plural, it is always represented as an array.) Various matchWildcard options allow you to match flexibly with * and ? characters, and various matchCaseSensitive options allow you to ignore case. The matchOperator option typically allows you to invert the result, so that the criteria succeeds if specified values don’t match.

The example above features a single contentType criteria. Once you define more than one, the rule needs a criteriaMustSatisfy field to set whether to match any or all criteria. This alternate example of the children array adds a random criteria to match half the requests for the specified contentType.

"children": [
    {
        "name": "Compress Half of Requests for Text Content",
        "criteriaMustSatisfy": "all",
        "criteria": [
            {
                "name": "contentType",
                "options": {
                    "matchOperator": "IS_ONE_OF",
                    "values": [
                        "text/html*",
                        "text/css*",
                        "application/x-javascript*"
                    ],
                    "matchWildcard": true,
                    "matchCaseSensitive": false
                }
            },
            {
                "name": "random",
                "options": { "bucket": 50 }
            }
        ],
        "behaviors": [
            {
                "name": "gzipResponse",
                "options": { "behavior": "ALWAYS" }
            }
        ]
    }
]

In this example, criteriaMustSatisfy is set to all. If it were set to any, the criteria would compress all text content, and half of all other content, including images that are already compressed. (This is almost certainly not what you want, and exemplifies the sort of bug that falls beyond what the API can identify for you, as discussed in the Debugging section.)

Note that rules do not provide any explicit support for else cases in response to criteria matches, but there are a couple of ways to implement them:

  • Specify exclusive pairs of match criteria: From the example above, the first rule could specify a contentType criteria that matches HTML/CSS/JavaScript using a matchOperator of IS_ONE_OF. The second rule could specify the same contentType criteria, only with a matchOperator of IS_NOT_ONE_OF.

  • Override a parent rule’s behavior: In the random example above, if you were to apply some other behavior to the remaining half of the requests, you would need to do so as part of the parent rule. If the parent rule enables a behavior that shouldn’t apply to the child, the child rule needs to specify the behavior again specifically to disable it.

Overall, the rules for how rules work are very simple. They are evaluated from top to bottom. A rule first evaluates its criteria, then executes its behaviors and children if the set of criteria matches. If any behavior is specified more than once within a set of executing rules, the last one overrides those that precede it. In some cases the ordering of different behaviors that perform similar functions may also matter. In other cases you can re-use the same behavior to do different things that don’t conflict with each other, for example, by modifying one HTTP header and then a different one.

Based on the newly added custom hostname discussed in Create a New Edge Hostname, you would typically add a corresponding set of rules. Appending this simple example to the rule’s array of children as part of a PUT request tests the hostname and assigns a different CP code to report on and separately bill for the custom site’s traffic.

{
    "name": "Custom Site",
    "criteria": [
        {
            "name": "hostname",
            "options": {
                "matchOperator": "IS_ONE_OF",
                "values": [ "custom.example.com" ]
            }
        }
    ],
    "behaviors": [
        {
            "name": "cpCode",
            "options": {
                "value": {
                    "id": 54321,
                    "name": "custom site"
                }
            }
        }
    ]
}

TIP: While the hostname criteria matches hostnames, the clientIp criteria matches IP addresses.

Once you’ve completed work on your rule tree, a PUT request with the revised data saves it:

PUT /papi/v0/properties/prp_175780/versions/3/rules/?contractId=ctr_1-1TJZH5&groupId=grp_15225

If the API detects any problems with the data, they are noted as part of the response, and you need to either fix or acknowledge them before you activate the property with that rule tree. See the Activate a Property operation. For details on the range of problems you may encounter when modifying a rule tree, see the Debugging section.

Advanced and Locked Features

In addition to its name and component options, special types of behavior and criteria objects may feature these additional members:

  • A uuid string signifies an advanced feature. Advanced behaviors and criteria are read-only, and can only be modified by Akamai representatives. They typically deploy metadata customized for you, whose functionality falls outside the predefined guidelines of what other read/write behaviors can do. Such metadata might also cause problems if executed outside of its intended context within the rule tree. (Advanced features are identified as read-only in the Behaviors and Criteria references.)

  • If a locked boolean member is true, it indicates a behavior or criteria that your Akamai representative has locked so that you can’t modify it. You typically arrange with your representative to lock certain behaviors to protect sensitive data from erroneous changes. Any kind of behavior or criteria may be locked, including writable ones.

When modifying rule trees, you must preserve the state of any uuid or locked members. You receive an error if you try to modify or delete either of these special types of feature. You can reposition regular features relative to these special ones, for example by inserting them within the same rule, but each rule’s sequence of special features must remain unchanged.

Additionally, rule objects may indicate the presence of special features:

  • A uuid member present on a rule object indicates that at least one of its component behaviors or criteria is advanced and read-only. You need to preserve this uuid as well when modifying the rule tree.

  • A criteriaLocked member enabled on a criteria rule by your Akamai representative means that you may not insert additional criteria objects within the sequence. This typically keeps complex logical tests from breaking. Preserve the state of criteriaLocked when modifying the rule tree.

Inserting Variables

For many behavior and criteria option fields, you can inject variable text, custom values that interpret when the property executes at runtime. You can invoke a set of built-in variables to capture contextual information about the client’s request, define your own variables, assign values to them based on these built-in variables or various other inputs, and use transform functions to modify their value at any point throughout the rule tree. You can perform conditional logic based on the variable’s value, and catch any unforeseen runtime errors.

Variables allow you to implement functionality that previously was only possible by injecting advanced custom XML metadata, a process requiring assistance from your Technical Support representative. Variables may not completely replace advanced metadata functionality but can greatly reduce the need.

Throughout the Behaviors and Criteria references, any option fields that allow you to inject variable text are marked allows variables. Within any of those option’s string values, you invoke variable names within pairs of {{}} delimiters. This example of a redirectPlus behavior option invokes the original request’s filename and concatenates it after a static string:

"destination": "/fixed/path/to/{{builtin.AK_FILENAME}}"

Note that, to accommodate the injection of variable strings, some options that reference conceptually numeric data are implemented instead as string types.

When inserting variables into text, you refer to them within a common namespace, in this case builtin for read-only system variables, followed by the unique variable name that is ultimately distributed in the XML metadata. The {{builtin.AK_FILENAME}} variable inserted above translates to %(AK_FILENAME) in XML metadata.

Built-in System Variables

The following lists all the built-in system variables available to you. For any of these items that are optional, such as filename extensions, the inserted variable may yield a blank string. Note that the AKA prefix for the first variable listed varies from all others.

Name Description
AKA_PM_CACHEABLE_OBJECT Either true if the requested object is cacheable, or false if not.
AK_BASE_URL The incoming request’s URL path, without filename and extension.
AK_CLIENT_IP Client IP address as seen by the Akamai server, possibly overridden by X-Forwarded-For or Akamai-Client-IP request headers.
AK_CLIENT_REAL_IP The client IP address as seen by the Akamai server, ignoring any request headers.
AK_CLIENT_RTT Milliseconds elapsed for the TCP round-trip (RTT) between client and edge server.
AK_CLIENT_TRANSFER_TIME Milliseconds elapsed to transfer content from edge to client. This value is only available after the client response completes. Applies only to custom log fields.
AK_CLIENT_TURNAROUND_TIME Milliseconds elapsed for the combined initial request (AK_CLIENT_RTT) plus the response’s transfer time (AK_CLIENT_TRANSFER_TIME). This value is only available after the client response completes. Applies only to custom log fields.
AK_CONNECTED_CLIENT_IP The IP on the TCP socket, either client or a redirecting ghost.
AK_CPCODE The CP code associated with the request.
AK_CURRENT_TIME The epoch time when edge metadata is applied to the request. If necessary, use the setVariable behavior to convert epoch time values to other time formats.
AK_DOMAIN The hostname without the initial subdomain, such as example.com when requesting www.example.com.
AK_EXTENSION The filename extension of the incoming request.
AK_FILENAME The complete filename of the incoming request.
AK_FIREWALL_ALERTED_RULES With webApplicationFirewall enabled, a colon-separated list of IDs for firewall rules that triggered an alert for the current request.
AK_FIREWALL_DENY_RULEID With webApplicationFirewall enabled, the ID for a firewall rule set to deny the request when the rule triggers.
AK_FIREWALL_DETECTED_RULES With webApplicationFirewall enabled, a colon-separated list of IDs for all firewall rules that apply to the request.
AK_GHOST_IP The IP address on which end client requests are received, and ultimately resolve for the end user.
AK_GHOST_SERVICE_IP The edge server IP address used to forward a request, also commonly known as the machine IP. This is the IP address the origin server sees as the client IP when it receives a request from the edge.
AK_HOST_CNAME_CHAIN A space-delimited list of the CNAME chain provided by DNS lookup on the incoming Host header.
AK_HOST The incoming request’s hostname.
AK_METHOD The request method, such as GET, PUT, POST, or HEAD.
AK_ORIGINAL_URL The original URL before any processing by Akamai Edge servers.
AK_PATH The original URL path as seen by the Akamai Edge server.
AK_PROTOCOL_NEGOTIATION The protocol negotiated with the client when NPN or ALPN is in use. Under HTTP, possible values are http/1.1 or http/1.0. For HTTP2, values are h2-14 or h2. For SPDY, values are spdy/3.1, spdy/3 or spdy/2.
AK_QUERY The URL’s entire query string.
AK_REQUEST_ID Unique identifier for each request on the edge server, the same as reported in logs.
AK_SCHEME The request scheme, either http or https.
AK_SLOT The incoming request’s slot number.
AK_TLS_CIPHER_NAME For HTTPS and SPDY requests, specifies the name of the cipher used for the SSL connection, otherwise NO-CIPHER for HTTP requests.
AK_TLS_ENCRYPTION_BITS Bits of encryption used for the request.
AK_TLS_PREFERRED_CIPHERS The value of the request’s security:essl.slot-assignment.preferred-ciphers tag.
AK_TLS_SNI_NAME The SNI name submitted by the client.
AK_TLS_VERSION The TLS version used for the connection.
AK_URL The incoming request’s entire URL.

Declaring Variables

While the built-in system variables described above are read-only, you can create and modify your own set of user variables. You can base their values on built-in system variables or other data about the request’s context, then transform them as described below.

First you need to declare the variable within the default rule’s variables array, otherwise you get an error when you later try to assign to them or invoke them in option values. The example below defines a single variable whose unique underlying name is VAR_NAME. Variable names may only feature alphanumeric and underscore characters. Uppercase is recommended by convention but is not required.

{
    "rules": {
        "name": "default",
        "options": {
            "is_secure": false
        },
        "variables": [
            {
                "name": "VAR_NAME",
                "value": "default value",
                "description": "This is a sample Property Manager variable.",
                "hidden": false,
                "sensitive": false
            }
        ],
        "criteriaMustSatisfy": "all",
        "criteria": [],
        "behaviors": [],
        "children": []
    }
}

The variable declaration object specifies these members:

Member Type Description
Required
name String The underlying root name of the variable, which must be unique within the set of variables.
hidden Boolean When enabled, the variable is suppressed from session response headers, often used to test content as described in the Debugging section.
sensitive Boolean When enabled, the variable is suppressed from session responses as hidden ones, but it also can’t be invoked within any behaviors that assign values to cookies or response headers. You also can’t assign a sensitive variable to another one that is not sensitive, and you can’t add it to custom logging fields. Use this more stringent option for any personally identifiable information, typically after initially testing on the staging network.
Optional
description String Text for you to keep track of how the variable is used.
value String Initializes a default value. Omitting this member equates to initializing an empty string.

There are three different ways variable names appear:

  • Within the variables declaration, you specify the base VAR_NAME.

  • When you modify the variable with setVariable or match it with matchVariable as described below, you add a PMUSER_ prefix to refer to the variable name as PMUSER_VAR_NAME. (In activated metadata, this appears as %(PMUSER_VAR_NAME).)

  • When you insert the variable as an expression within behavior and criteria option fields, you need an additional user. namespace prefix: {{user.PMUSER_VAR_NAME}}.

Assigning Variables

Once you declare a variable within the default rule’s variables array, you assign a value to it using the setVariable behavior, which you can place anywhere as appropriate within the rule tree. This example assigns the value of the built-in AK_EXTENSION variable to store the request’s file extension in a user variable named EXT. To assign a variable, specify the variableName you want to modify, specify the valueSource as EXPRESSSION, then as the variableValue inject the variable using the same syntax as in any other option field. In this example, setting the TRANSFORM to NONE means you don’t yet want to change the value.

{
    "name": "setVariable",
    "options": {
        "variableName": "PMUSER_EXT",
        "valueSource": "EXPRESSION",
        "variableValue": "{{builtin.AK_EXTENSION}}",
        "transform": "NONE"
    }
}

The matchVariable criteria allows you to test a variable’s value at runtime. This example set of criteria tests if the request is for a filename with no extension, but requiring a filename and thus excluding any directory-style URLs that end with a slash character:

"criteriaMustSatisfy": "all",
"criteria": [
  {
    "name": "matchVariable",
    "options": {
      "variableName": "AK_FILENAME",
      "mode": "IS_NOT_EMPTY"
    }
  },
  {
    "name": "matchVariable",
    "options": {
      "variableName": "PMUSER_EXT",
      "mode": "IS_EMPTY"
    }
  }
]

NOTE: While the matchVariable criteria offers a way to account for known error scenarios, see the Debugging section for more information on the variableError criteria, which allows you to detect other unforeseen error scenarios that only reveal themselves at runtime.

In response to the test criteria above, one of the rule’s accompanying behaviors may assign a static EXPRESSION of html for use as a default file extension:

{
    "name": "setVariable",
    "options": {
        "variableName": "PMUSER_EXT",
        "valueSource": "EXPRESSION",
        "variableValue": "html",
        "transform": "NONE"
    }
}

You can assign values from many other sources besides built-in system variables. Setting the setVariable behavior’s valueSource to EXTRACT gives you the option to assign more specific values from the request. The extractLocation may specify header, cookie, and query parameter names, certificates, path directory components, and any embedded path parameters. Setting extractLocation to EDGESCAPE allows you to leverage a great deal of location-based data based on this request. The sample behaviors below assign the client request’s geographic location to a pair of LAT and LONG variables.

{
    "name": "setVariable",
    "options": {
        "variableName": "PMUSER_LAT",
        "valueSource": "EXTRACT",
        "extractLocation": "EDGESCAPE",
        "locationId": "LAT",
        "transform": "NONE"
    }
},
{
    "name": "setVariable",
    "options": {
        "variableName": "PMUSER_LONG",
        "valueSource": "EXTRACT",
        "extractLocation": "EDGESCAPE",
        "locationId": "LONG",
        "transform": "NONE"
    }
}

In addition, when the valueSource is set to GENERATE, you can incorporate various random numbers and hex strings into variables. See the setVariable behavior for details on all the sources of information you can assign to variables.

Modifying Variables

In all of the examples above, the transform option is set to NONE, which leaves the value unchanged after assigning it, but it supports a large set of functions that in effect offers an embedded programming language. Transform functions allow you to:

  • do basic arithmetic
  • perform bitwise operations
  • convert case
  • locate and generate substrings
  • make regular expression substitutions
  • perform many conversions and encodings

See the setVariable behavior for comprehensive details.

To modify a value within any setVariable behavior, set its transform function along with any necessary dependencies. Each behavior can only transform its value once, so to transform a value more than once you need to form a chain of setVariable behaviors. Each subsequent behavior must reassign the transformed value back to itself, then perform an additional transformation.

This simple example modifies a LANG user variable, assigning it the value of the request’s Accept-Language header. The initial behavior performs a SUBSTRING transform to limit the string to the initial two-letter code. The second behavior reassigns {{user.PMUSER_LANG}} back into LANG, then runs the UPPER transform to convert to uppercase.

{
    "name": "setVariable",
    "options": {
        "variableName": "PMUSER_LANG",
        "valueSource": "EXTRACT",
        "extractLocation": "CLIENT_REQUEST_HEADER",
        "headerName": "Accept-Language",
        "transform": "SUBSTRING",
        "startIndex": "1",
        "endIndex": "2"
    }
},
{
    "name": "setVariable",
    "options": {
        "variableName": "PMUSER_LANG",
        "valueSource": "EXPRESSION",
        "variableValue": "{{user.PMUSER_LANG}}",
        "transform": "UPPER"
    }
}

For more details on how to use variables within the Property Manager portal, see Variables.

Understanding Rule Formats

PAPI provides rule format schema objects that define the features you may enable under a product. This section shows how to interpret a rule format and use it to validate a rule tree or research available features.

The schema’s relevant content is nested within the outer object’s definitions member, which is empty in this example:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "rules": {
            "$ref": "#/definitions/toprule"
        }
    },
    "required": [ "rules" ],
    "definitions": {
    }
}

The top level of the schema specifies only that the rule tree must feature a rules member, specified indirectly within a large definitions section that the example above does not display. The toprule itself specifies an object that must feature a name. While these specify the object’s basic structure, the definition’s catalog member contains available features, separately within the behaviors and criteria sub-trees. Each of those object’s keys list supported features, and the values define their components.

NOTE: The features specified in the rule format represent all the behaviors and criteria the product supports, not necessarily those currently enabled for your account. Each product specifies a baseline set, with other more specialized features enabled via add-on modules, as discussed in PAPI Concepts. To determine the set of features currently available on your account, saving a property that specifies them returns an error that notifies you otherwise.

The following shows a typical behavior definition for caching, along with its component options, some of whose data types are referenced elsewhere within the schema.

"caching": {
    "type": "object",
    "properties": {
        "name": {
            "enum": [ "caching" ]
        },
        "uuid": {
            "type": "string"
        },
        "options": {
            "type": "object",
            "properties": {
                "behavior": {
                    "enum": [ "max-age", "no-store", "bypass-cache", "both", "cc", "expires" ],
                    "default": "max-age"
                },
                "mustRevalidate": {
                    "enum": [ "off", "on" ],
                    "default": "off"
                },
                "ttl": {
                    "$ref": "#/definitions/catalog/option_types/duration"
                },
                "defaultTtl": {
                    "$ref": "#/definitions/catalog/option_types/duration"
                }
            }
        }
    }
}

Understand the limitations of the rule format’s available data. While each option’s basic data type is specified, additional validation logic is not necessarily available within the schema, and may be implemented as part of the API’s back end. The rule format also does not represent dependencies among the options. For example, many behaviors feature a high-level enabled switch. When disabled, the API typically ignores any other specified option. When enabled, there may be other contextual dependencies among the options. The Behaviors and Criteria references detail most of these dependencies.

Rule formats often specify only minimal validation criteria. For example, the rule format’s option_types section describes custom data formats, such as the following to represent a CP code object with a required id member:

"cpCode": {
    "type": "object",
    "properties": {
        "id": {
            "type": "number"
        }
    },
    "required": [ "id" ]
},

The rule format does not specify the name member that also typically appears within a cpcode object. It does not specify what happens if you omit the name, or supply other members unknown to the API’s back end. The back end may behave slightly differently over time, even if you freeze the API’s set of features.


Last modified: 6/7/2017