Edgio

Conditional Routes

Define a rule that uses advanced condition-based logic through:
This documentation expects you to be familiar with defining simple rules through .get(), .match() and .post() Router methods, as explained in Route Criteria and Conditions and Route Features documentation.

Using the .if(), .elseif(), and .else() Methods

The Router class includes the conditional methods .if(), .elseif(), and .else() to implement if/then logic on requests. You can chain these methods to craft sophisticated routing rules. For enhanced conditions, you can embed logical operator functions within the .if() and .elseif() criteria.
Both the .if() and .elseif() methods have the same signature when it comes to defining conditions and features. The first argument is of type ConditionCriteria, designed to specify one or more conditions. The subsequent (N) arguments are of the ConditionalParam type, letting you define various features or routers, especially for nested rules.
Likewise, the .else() method takes any number (N) of arguments of the ConditionalParam type, allowing you to outline features or nested rules.
It’s important to note the chaining order of the conditional methods.
  • .if() does not require a following .elseif() or .else() method.
    JavaScript
    1router.if(/* ... */).get(/* ... */).match(/* ... */);
  • .else() must follow directly after the .if() method or after an .elseif() method.
    JavaScript
    1router.if(/* ... */).else(/* ... */).get(/* ... */).match(/* ... */);
  • .elseif() must follow directly after the .if() method or another .elseif() method.
    JavaScript
    1router
    2 .if(/* ... */)
    3 .elseif(/* ... */)
    4 .else(/* ... */)
    5 .get(/* ... */)
    6 .match(/* ... */);
The following example is invalid as .elseif() and .else() are not following directly after .if() or .elseif():
JavaScript
1router
2 .if(/* ... */)
3 .get(/* ... */)
4 .elseif(/* ... */) // must follow directly after .if() or .elseif()
5 .match(/* ... */)
6 .else(/* ... */); // must follow directly after .if() or .elseif()

IF / ELSE Condition

JavaScript
1import {Router} from '@edgio/core';
2
3export default new Router()
4 .if(
5 {
6 path: '/foo',
7 },
8 {
9 response: {
10 set_response_body: 'Hello, /foo!',
11 },
12 }
13 )
14 .else({
15 response: {
16 set_response_body: 'Hello, world!',
17 },
18 });
In this example, if the request path is /foo, the response body will be Hello, /foo!. For all other request paths, the response body will be Hello, world!.

IF / ELSEIF / ELSE Condition

JavaScript
1import {Router} from '@edgio/core';
2
3export default new Router()
4 .if(
5 {
6 path: '/foo',
7 },
8 {
9 response: {
10 set_response_body: 'Hello, /foo!',
11 },
12 }
13 )
14 .elseif(
15 {
16 path: '/bar',
17 },
18 {
19 response: {
20 set_response_body: 'Hello, /bar!',
21 },
22 }
23 )
24 .else({
25 response: {
26 set_response_body: 'Hello, world!',
27 },
28 });
In this example, if the request path is /foo, the response body will be Hello, /foo!. If the request path is /bar, the response body will be Hello, /bar!. For all other request paths, the response body will be Hello, world!.

Logical .and(), .or(), not() Functions

Using the .and(), .or() and .not() helper functions, you can create more complex logic within your conditional rules. These functions may be imported from the @edgio/core package.
JavaScript
1import {Router, and, or, not} from '@edgio/core';
2
3export default new Router()
4 .if(
5 or(
6 {
7 path: '/foo',
8 },
9 {
10 path: '/bar',
11 }
12 ),
13 {
14 response: {
15 set_response_body: 'Hello, /foo or /bar!',
16 },
17 }
18 )
19 .elseif(
20 and(
21 {path: '/baz'},
22 not({
23 method: 'POST',
24 })
25 ),
26 {
27 response: {
28 set_response_body: 'Hello, /baz with a non-POST method!',
29 },
30 }
31 )
32 .else({
33 response: {
34 set_response_body: 'Hello, world!',
35 },
36 });
In this example, if the request path is /foo or /bar, the response body will be Hello, /foo or /bar!.
If the request path is /baz and the request method is not POST, the response body will be Hello, /baz with a non-POST method!.
For all other request paths, the response body will be Hello, world!.

Nested Rules

Nested rules are applied to an existing conditional route. They are a set of child rules under a parent .if(), .elseif(), or .else() method. Nested rules are defined using a new Router instance.
Nested rules must use a new Router instance. You cannot use the same Router instance for both the parent and nested rules.
For example, you can use rules to split traffic to different origins based on a cookie, and nested rules to handle requests to a specific path. The example below will send traffic to different origins depending on the cookie value, and then apply nested rules to rewrite the URL path for requests to /assets/* to /public/assets/*:
JavaScript
1import {Router} from '@edgio/core';
2
3export default new Router()
4 .if(
5 {cookies: {experience: 'new'}},
6 {origin: {set_origin: 'new_origin'}},
7 new Router().match('/assets/:path*', {
8 url: {
9 url_rewrite: [
10 {
11 source: '/assets/:path*',
12 destination: '/public/assets/:path*',
13 syntax: 'path-to-regexp',
14 },
15 ],
16 },
17 })
18 )
19 .else({origin: {set_origin: 'legacy_origin'}});

Advanced Criteria

If you wish to utilize the .if(), .elseif(), and .else() methods but find that your criteria are not supported by RouteCriteria, consider using the edgeControlCriteria property. This property allows you to define more advanced criteria using object-literal notation and is of the type Matches. For a detailed specification of the Matches type, refer to the API reference.
The following example applies the nested logic if the device is a tablet and the HTTP request method is GET (combination of both criteria formats):
JavaScript
1import {Router, and} from '@edgio/core';
2
3export default new Router()
4 .if(
5 and(
6 {
7 edgeControlCriteria: {
8 "===": [
9 {
10 device: "is_tablet"
11 },
12 true
13 ]
14 },
15 { method: "GET" }
16 }
17 ),
18 new Router().if(/* ... */)
19 );

Using the .conditional() Method

Using the .conditional() method to define complex rules is no longer recommended. It’s advisable to use the .if(), .elseif(), and .else() methods instead.
For those with existing .conditional() calls, you can map them to the simpler .if() calls using the Export to EdgeJS functionality available in Edgio Console. For more information, consult the Rules documentation.
Let’s revisit the example from our Default Route Configuration section where we cached all requests to /api/*:
JavaScript
1// This file was added by edgio init.
2// You should commit this file to source control.
3import {Router, edgioRoutes} from '@edgio/core';
4
5export default new Router()
6 // Here is an example where we cache api/* at the edge but prevent caching in the browser
7 .match('/api/:path*', {
8 caching: {
9 max_age: '1d',
10 stale_while_revalidate: '1h',
11 bypass_client_cache: true,
12 service_worker_max_age: '1d',
13 },
14 })
15
16 // plugin enabling basic Edgio functionality
17 .use(edgioRoutes);
Using the example above for caching the /api/* path, we can rewrite the same route using the conditional() method. This method accepts a single argument of type Matches. You can see the full specification of the Matches type in the API reference.
JavaScript./routes.js
1import {Router} from '@edgio/core/router';
2
3export default new Router().conditional({
4 if: [
5 {
6 and: [
7 {
8 '===': [
9 {
10 request: 'method',
11 },
12 'GET',
13 ],
14 },
15 {
16 '==': [
17 {
18 request: 'path',
19 },
20 '/api/:path*',
21 ],
22 },
23 ],
24 },
25 {
26 caching: {
27 max_age: '1d',
28 stale_while_revalidate: '1h',
29 service_worker_max_age: '1d',
30 bypass_client_cache: true,
31 },
32 origin: {
33 set_origin: 'origin',
34 },
35 },
36 ],
37});
This is equivalent to the previous example. Broken down by line:
  • The if key is an array containing two objects. The first object defines the conditions that must be met using the and logic key. The second object defines the features to apply if all conditions are met.
    • The and array requires all the following conditions to be satisfied:
      • The HTTP request method strictly equals (===) GET
      • The request path is a simple match (==) /api/:path*. (eg. /api/foo or /api/foo/bar)
    • Assuming all conditions are met, the following features will be applied:
      • The request will be cached at the edge for one day.
      • The request will be forwarded to the origin when the cache is stale, and then cached for one day.
      • The request will be cached by the service worker for one day.

Types of Operators and Conditionals

Operators

The Boolean type is used as a logical operator in the if array. You may specify an and or or operator. The and operator requires all conditions to be met. The or operator requires only one condition to be met.
Currently, only a single and/or operator is supported. The following would be an invalid use of multiple operators:
JavaScript
1{
2 if: [
3 {
4 and: [
5 {
6 // conition
7 },
8 {
9 // condition
10 },
11 ],
12 or: [
13 {
14 // condition
15 },
16 ],
17 },
18 {
19 // features
20 },
21 ],
22}

Criteria Format

The criteria outline the conditions that a request must fulfill for certain features to be applied. In simple terms, they state: “If the request meets these conditions, apply the specified features.”
In the following example, we are using the === operator to check if a certain aspect of the request (RulesVariables) matches an expected value:
JavaScript
1{
2 '===': [ // This is a strict equality operator
3 {
4 request: 'method', // We are looking at the method of the request
5 },
6 'GET', // We expect the method to be 'GET'
7 ],
8};

Comparison Operators

OperatorDescription
==Simple match.
!=Negated simple match.
===Strict match.
!==Negated strict match.
<Less than.
<=Less than or equal to.
>Greater than.
>=Greater than or equal to.
inValue is in the array.
not_inValue is not in the array.
=~Regular expression match.
!~Negated regular expression match.
If your routes file contains old .conditional() calls, they can be simplified to .if() calls through export to EdgeJS functionality in Edgio Console. To learn more, see Rules documentation.