Introducing Edgio Applications v7Find out what's new.
Edgio
Edgio

Getting Started with CDN-As-Code

Upgrading from Edgio Applications version 6 or earlier may require significant changes to your CDN-as-code configuration as certain core legacy components have limited support. View our upgrading guide.
Our CDN-as-code approach to configuration allows you to configure CDN behavior using EdgeJS within a file (routes.[js|ts]) stored alongside your code. This allows you to leverage the power of source control for collaboration and to link your CDN configurations with specific versions of your web application.

Quick Start

Get started with CDN-as-code by either experimenting with:
Perform the following steps to use Edgio to improve the performance of your web application or website:
  1. Create a property. If you have already performed this step, proceed to the next step.
    Learn more.
  2. Use the Edgio CLI to initialize your property. If you have already performed this step, proceed to the next step.
    This step requires Node.js v16.x.
    Install the Edgio CLI, initialize your property, and then deploy it by running the following command from the root directory of your web application or website:
    Bash
    1npx @edgio/cli@latest init \
    2 --edgioVersion latest \
    3 --name <PROPERTY> \
    4 --deploy
    Replace <PROPERTY> with the name of the property defined in step 1. You should only use lower-case characters and replace spaces with dashes (e.g., my-property).
  3. Define routes that determine how Edgio will handle that traffic.
  4. Test your changes locally.
  5. Deploy your property to the Edgio network.

Routes File

The routes.[js|ts] file defines a set of routes. A route:
  • Identifies a set of requests by HTTP method, URL path, query string parameters, cookies, and request headers.
  • Determines how our CDN will handle the above requests. For example, you may configure those requests to be cached, prefetched, passed through without modification, or served as static content.
By default, our CLI automatically creates routes.js and edgio.config.js upon initializing a property (edgio init). If your web application supports TypeScript and it uses a framework for which we have a TypeScript implementation, then our CLI will create routes.ts instead of routes.js.

Default Route Configuration

By default, your routes.[js|ts] contains the following configuration:
JavaScript./routes.js
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);
The above configuration shows an example of how you can match all requests to the /api/ URL path and cache them at the edge for 1 day.

Routes

A route identifies a set of requests through any combination of URL path, HTTP method, cookies, request headers, and query string parameters. The following routes show various ways for identifying requests.
  • Match all requests:
    JavaScript
    1router.match('/:path*', {
    2 // route handler goes here
    3});
  • Match all GET requests whose URL path starts with /marketing/images/:
    JavaScript
    1router.get('/marketing/images/:path*', {
    2 // route handler goes here
    3});
  • Match all GET and POST requests whose URL path starts with /marketing/images/ and contain the sport request header set to basketball:
    JavaScript
    1router.match(
    2 {
    3 path: '/marketing/images/:path*',
    4 method: /GET|POST/i, // regular expression
    5 headers: {sport: /^basketball$/i}, // keys are header names; values are regular expressions
    6 },
    7 {
    8 // route features goes here
    9 }
    10);
Once you have identified a set of requests, you need to define how Edgio will handle those requests. The following routes show various ways in which requests can be processed.
  • Apply a caching policy to all requests and proxy cache misses to the origin backend:
    JavaScript
    1router.match('/:path*', {
    2 {
    3 caching: {
    4 max_age: "1h"
    5 },
    6 origin: {
    7 set_origin: "origin"
    8 }
    9 }
    10})
  • Set the images response header and proxy cache misses to the origin backend for all GET requests whose URL path starts with /marketing/images/:
    JavaScript
    1router.get('/marketing/images/:path*', {
    2 headers: {
    3 set_response_headers: {
    4 images: 'true',
    5 },
    6 },
    7 origin: {
    8 set_origin: 'origin',
    9 },
    10});
View additional examples.

Defining Routes

Routes are defined by calling a function on the Router object based on the HTTP method you intend to match. For example, you can handle a GET request a specific path or pattern using the Router.get(...) function. The router contains methods for all the supported HTTP methods. The following methods are available:
  • delete
  • get
  • head
  • match (matches any HTTP method)
  • options
  • patch
  • post
  • put
A full list of supported functions can be found in the Router API documentation.

Route Method Signature

Using .match() as an example, the method signature is as follows:
TypeScript
1match(
2 criteria: RouteCriteria | string | string[] | RegExp,
3 features: FeaturesParam
4)
The first argument criteria defines how to match a request. It can be a string (or array of strings), a regular expression, or an object of type RouteCriteria. For example, to match requests to the /api/* URL path, you could define the criteria as follows:
JavaScript
1// match by named parameter
2router.match('/api/:path*', {
3 // route features goes here
4});
5
6// match by regular expression
7router.match(/^\/api\/(.*)$/, {
8 // route features goes here
9});
10
11// match by `path` property
12router.match(
13 {
14 path: '/api/:path*',
15 },
16 {
17 // route features goes here
18 }
19);
All of the above examples are equivalent and show the various ways in which you can define the route criteria.
The second argument features, also referred to as the route handler, defines how to handle a request such as how to cache the response, how to proxy the request to the origin, or how to modify the request and response headers. This is an object of type Features and the full list of supported features can be found in the Features API reference.
We will now define a route by uncommenting the match() method in your routes.[js|ts] file. It should now look similar to the following configuration:
JavaScript./routes.js
1export default new Router()
2 // Here is an example where we cache api/* at the edge but prevent caching in the browser
3 .match('/api/:path*', {
4 caching: {
5 max_age: '1d',
6 stale_while_revalidate: '1h',
7 bypass_client_cache: true,
8 service_worker_max_age: '1d',
9 },
10 })
11
12 // plugin enabling basic Edgio functionality
13 .use(edgioRoutes);
The above route matches all requests that start with /api/ and instructs Edgio to:
  • Cache those requests on our network for one day.
  • Allow us to serve stale content for one hour.
  • Instruct the browser to treat the response as immediately stale.
  • Allow prefetched requests to be served from cache for one day.
  • Proxy those requests to your origin backend when we cannot serve them from cache.
We will now add a route that applies the same caching policy to all JavaScript (i.e., .js and .mjs) and CSS files.
JavaScript./routes.js
1// Cache stylesheets and scripts, but prevent browser caching
2router.match('/:path*/:file.:ext(js|mjs|css)', {
3 caching: {
4 max_age: '1d',
5 stale_while_revalidate: '1h',
6 service_worker_max_age: '1d',
7 bypass_client_cache: true,
8 },
9 headers: {
10 set_response_headers: {
11 'cache-control': 'public, max-age=86400',
12 },
13 remove_origin_response_headers: ['set-cookie'],
14 },
15 origin: {
16 set_origin: 'origin',
17 },
18});
The above route instructs Edgio to perform the following actions for all requests whose file extension matches js, mjs, or css:
  • Set the cache-control response header to: cache-control: public, max-age=86400
  • Remove the set-cookie response header. Edgio will not cache a response when the set-cookie response header is present.
  • Apply the caching policy.
  • Proxy these requests to your origin backend when we cannot serve them from cache.
Your routes.[js|ts] should now look similar to the following:
JavaScript./routes.js
1import {Router} from '@edgio/core/router';
2
3export default new Router()
4 .match('/api/:path*', {
5 caching: {
6 max_age: '1d',
7 stale_while_revalidate: '1h',
8 service_worker_max_age: '1d',
9 bypass_client_cache: true,
10 },
11 origin: {
12 set_origin: 'origin',
13 },
14 })
15
16 // Cache stylesheets and scripts, but prevent browser caching
17 .match('/:path*/:file.:ext(js|mjs|css)', {
18 caching: {
19 max_age: '1d',
20 stale_while_revalidate: '1h',
21 service_worker_max_age: '1d',
22 bypass_client_cache: true,
23 },
24 headers: {
25 set_response_headers: {
26 'cache-control': 'public, max-age=86400',
27 },
28 remove_origin_response_headers: ['set-cookie'],
29 },
30 origin: {
31 set_origin: 'origin',
32 },
33 })
34
35 // plugin enabling basic Edgio functionality
36 .use(edgioRoutes);

Conditional Routes

Conditional routes allow you to apply rules to a request using advanced if/then logic by the means of logical and comparison operators.

Using the .conditional() method

Using the previous 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 array contains two objects. The first object defines an array of conditions that must be met using the and logic operator. 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.

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}

Conditionals

Conditionals define the expectations that must be met, using comparison operators, for the features to be applied to the request. This example of a single conditional identifies the type of comparison to take against the RulesVariables and the expected value:
JavaScript
1{
2 '===': [ // comparison operator
3 {
4 request: 'method', // rules variable
5 },
6 'GET', // expected value
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.

Example

This example shows multiple conditionals that use various comparison operators and rules variables:
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.header': 'x-test',
11 },
12 '^foo$',
13 ],
14 },
15 {
16 and: [
17 {
18 '!==': [
19 {
20 request: 'method',
21 },
22 'DELETE',
23 ],
24 },
25 {
26 and: [
27 {
28 '==': [
29 {
30 request: 'path',
31 },
32 '/api/v:version/:path*',
33 ],
34 },
35 {
36 and: [
37 {
38 not_in: [
39 {
40 request: 'path',
41 },
42 ['/api/v1', '/api/v2'],
43 ],
44 },
45 {
46 and: [
47 {
48 '!~': [
49 {
50 'request.cookie': 'user_level',
51 },
52 '^level_(1|2)$',
53 ],
54 },
55 {
56 and: [
57 {
58 '===': [
59 {
60 device: 'is_robot',
61 },
62 true,
63 ],
64 },
65 {
66 '>=': [
67 {
68 device: 'resolution_height',
69 },
70 800,
71 ],
72 },
73 ],
74 },
75 ],
76 },
77 ],
78 },
79 ],
80 },
81 ],
82 },
83 ],
84 },
85 {
86 caching: {
87 bypass_client_cache: true,
88 service_worker_max_age: '1d',
89 max_age: {
90 200: '1d',
91 },
92 stale_while_revalidate: '1h',
93 },
94 origin: {
95 set_origin: 'origin',
96 },
97 },
98 ],
99});

Testing Locally

You may run Edgio in local development mode to preview your website on your local machine prior to deployment. Local development mode allows for rapid development by allowing you to quickly test changes prior to deployment.
  1. From the command line or terminal, type edgio dev.
  2. Preview your website by loading https://127.0.0.1:3000 from within your preferred web browser.

Deploying Your Property

Evaluate site performance and QA functionality by deploying your property to Edgio. Run the following command from your property’s root directory:
Bash
1edgio deploy
Assess performance and caching behavior from the Edgio Console. Fine-tune your configuration by adding routes and then redeploying your property. Once you are ready to serve production traffic through Edgio, update your site’s DNS to point to our service.
Learn more.

Examples

Use our sample website to gain hands-on experience on how to set up Edgio Performance. Specifically, you can browse our sample websites, view their source code, and even experiment on them by deploying them to Edgio.
Simple Example
This example demonstrates a basic Edgio configuration for publicdomainreview.org. It contains two routes that cache content according to their file extension.

Issues?

If you have any issues during this process, check our forums for assistance.