Welcome to Akamai Edge Compute demo site!

Powered by Linode updated logo

Learn how you could leverage Akamai Edge Computing solutions to boost performance and create great user experience by enabling developers to build web applications closer to end users. Also learn various ways you can implement Edge Compute into your site or web application.

These examples illustrate how you can use Akamai serverless solutions to create great user experiences for your users. Click on each use case to review a code snippet and a live example, or head over to Github to see the full source code.

Use Cases

Checkout some of the use cases below for both EdgeWorkers & EdgeKV working in action.

HelloWorld using EdgeWorkers

With this example you learn the basics of creating, deploying and debugging an EdgeWorker that generates a simple html page at the Edge and adds a response header.

Outcome :

Page Displaying Hello World from EdgeWorkers.

  • View this example on Github
  • // Import logging module
    import { logger } from 'log';
    
    export function onClientRequest(request) {
        // Outputs a message to the X-Akamai-EdgeWorker-onClientRequest-Log header.
        logger.log('Responding with hello world from the path: %s', request.path);
        request.respondWith(200, {}, 'Hello World From Akamai EdgeWorkers');
    }
    
    export function onClientResponse(request, response) {
        // Outputs a message to the X-Akamai-EdgeWorker-onClientResponse-Log header.
        logger.log('Adding a header in ClientResponse');
        response.setHeader('X-Hello-World', 'From Akamai EdgeWorkers');
    }

    GeoLocation using EdgeWorkers

    This example implements a microservice GEO-Location API call that returns location information about the client where the request originates.

    Outcome :

    Location information about the client where the request originates.

  • View this example on Github
  • export function onClientRequest(request) {
        var info = {};
    
        info.continent = (request.userLocation.continent) ? request.userLocation.continent : 'N/A';
        info.country = (request.userLocation.country) ? request.userLocation.country : 'N/A';
        info.zip = (request.userLocation.zipCode) ? request.userLocation.zipCode : 'N/A';
        info.region = (request.userLocation.region) ? request.userLocation.region : 'N/A';
        info.city = (request.userLocation.city) ? request.userLocation.city : 'N/A';
    
        info.source = 'Akamai EdgeWorkers';
        request.respondWith(200, {}, JSON.stringify({
            geoInfo: info
        }));
    }

    E-commerce Categories using EdgeWorkers

    This use-case is the projection forward of a whole endpoint from origin, perhaps useful for slow-changing and simple data that can be statically included in the code.This EdgeWorker tests for /commerce/categories in the URI path in order to act. It will then respond to a GET parameter named search by running a case-insensitive regex against each title and desc field, and a numeric comparison against each id, and returning an array of matching category entities, serialized as JSON. Because the response is generated at the Edge, origin will not be contacted, and the request will be fully resolved at the first Edge server that answers it.

    Outcome :

    Return JSON reponse for the selected item.

  • View this example on Github
  • import URLSearchParams from 'url-search-params';
    
    const categories = [{
            title: 'Furniture',
            id: 1040,
            desc: 'Desks, chairs, couches, tables, lamps, rugs.'
        },
        {
            title: 'Shoes',
            id: 1060,
            desc: 'Athletic shoes, sneakers, booties, flats, heels, sandals, slippers.'
        },
        {
            title: 'Baby',
            id: 1090,
            desc: 'Diapers, pacifiers, newborn clothes, toys, nursery.'
        },
        {
            title: 'Beauty',
            id: 1110,
            desc: 'Makeup, skin care, perfume, cologne, hair care, shampoo, conditioner.'
        },
        {
            title: 'Jewelry',
            id: 1150,
            desc: 'Watches, bracelets, necklaces, earings, gemstones, pearls, diamonds, rings.'
        },
        {
            title: 'Electronics',
            id: 1250,
            desc: 'Smartphones, tablets, fitness trackers, smart pens, computers, monitors.'
        }
    ];
    
    export function onClientRequest(request) {
        if (request.path.match(/\/commerce\/categories/)) {
            const params = new URLSearchParams(request.query);
            const search = params.get('search');
            if (search) {
                const re = new RegExp(search, 'i');
                var data = categories.filter(el => el.title.match(re) || el.desc.match(re) || el.id === search);
                request.respondWith(200, {
                    'Content-Type': ['application/json']
                }, JSON.stringify(data));
            }
        }
    }

    JA3 Fingerprinting using EdgeWorkers

    Calculates JA3 Fingerprint using EdgeWorkers.TLS fingerprinting is a technique that associates TLS library with parameters from a TLS ClientHello via a database of curated fingerprints to identify malware and vulnerable applications for better network visibility. JA3 algorithm takes a collection of settings from the SSL “ClientHello” such as SSL/TLS version, accepted cipher suites, list of extensions, accepted elliptical curves/formats, as well as others. For compactness, the JA3 string is hashed with MD5. The idea here is to calculate JA3 Fingerprint using EdgeWorkers so that customers can deny requests from services with suspicious JA3 Fingerprint and credentials, without contacting origin servers even on cacheable contents.

    Outcome :

    The EdgeWorkers code gets TLS ClientHello data from PMUSER_TLS_CLIENT_HELLO and sets JA3 Fingerprint to PMUSER_JA3_FINGERPRINT

  • View this example on Github
  • import * as util from './util.js';
    
    export function onClientRequest(request) {
      const client_hello = request.getVariable('PMUSER_TLS_CLIENT_HELLO');
      const buffer = util.base64toUint8Array(client_hello);
    
      const JA3_fingerprint = util.getJA3Fingerprint(buffer);
      request.setVariable('PMUSER_JA3_FINGERPRINT', JA3_fingerprint);
    
      return JA3_fingerprint;
    }

    Use a Content Security Policy to cut latency, not security

    A Content Security Policy (CSP) is a security feature implemented in web browsers. It protects websites and web applications from attacks such as cross-site scripting (XSS) and data injection. To provide protection, CSP controls and limits the source of the various types of content loaded and executed on a web page. This content includes scripts, stylesheets, and images.EdgeWorkers provides numerous performance benefits for CSPs. These policies also need to complement the security measures on the application server-side.

    Note: You can find the cspPolicyParser.js in the link to Github

    Outcome :

    For every request a nonce is generated, added to the CSP header, and then injected into the HTML source.

    import {parsePolicy} from './cspPolicyParser.js';
    import {HtmlRewritingStream} from 'html-rewriter';
    import {httpRequest} from 'http-request';
    import {createResponse} from 'create-response';
    import {crypto} from 'crypto';
    import {btoa} from "encoding";
    import {logger} from 'log';
    
    export async function responseProvider(request) {
    
        //Step 1: Calculate the Nonce
        let array = new Uint32Array(1);
        crypto.getRandomValues(array);
        let stringToEncode = array[0].toString();
        let encodedData = btoa(stringToEncode);
        let headerNonce = 'nonce-' + encodedData;
        logger.log('nonce: %s', headerNonce);
    
        //Step 2: Replace the origin nonce with our generated nonce in the CSP response header
        const headers = request.getHeaders();
        let options = {};
        let htmlResponse = await httpRequest("/xyz/csp/index.html", options);
        if (!htmlResponse.ok) {
            return createResponse(500, {}, `Failed to fetch doc: ${htmlResponse.status}`);
        }
        let responseHeaders = htmlResponse.getHeaders();
        let originCSPHeader = htmlResponse.getHeader('Content-Security-Policy')[0];
        const parsedPolicy = parsePolicy(originCSPHeader);
        let parsedPolicyElement = parsedPolicy['script-src'][0].toString();
        let newCspHeader = originCSPHeader.replace(parsedPolicyElement, "'" + headerNonce + "'");
        responseHeaders['content-security-policy'] = [newCspHeader];
    
        //Step 3: Rewrite the HTML with our generated nonce
        let rewriter = new HtmlRewritingStream();
        rewriter.onElement('[nonce=' + parsedPolicyElement + ']', el => {
            el.setAttribute('nonce', encodedData, {quote: "'"})
        });
    
        return createResponse(200, getSafeResponseHeaders(responseHeaders), htmlResponse.body.pipeThrough(rewriter));
    }
    
    // Add/remove unsafe headers from this list as required. This headers will be removed form origin response before sending to client.
    const UNSAFE_RESPONSE_HEADERS = ['content-length', 'transfer-encoding', 'connection', 'vary',
        'accept-encoding', 'content-encoding', 'keep-alive',
        'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'upgrade', 'host'];
    
    function getSafeResponseHeaders(headers) {
        for (let unsafeResponseHeader of UNSAFE_RESPONSE_HEADERS) {
            if (unsafeResponseHeader in headers) {
                delete headers[unsafeResponseHeader];
            }
        }
        return headers;
    }

    EdgeWorkers - HTML Rewriter

    In this example, we leverage EdgeWorkers html-rewriter to efficiently generate dynamic HTML content by combining JSON data from an API endpoint with an HTML template. Additionally, if the request is made by a logged-in user, a discount code will be dynamically incorporated into the rendered document. By performing these operations at the Edge with EdgeWorkers, we enhance site performance, offload server resources, and unlock SEO advantages. Furthermore, the template, JSON data, and rendered content can all be efficiently cached at the Edge, further optimizing response times and optimizing the overall site experience.

    Outcome :

    import { logger } from 'log';
    import { HtmlRewritingStream } from 'html-rewriter';
    import { httpRequest } from 'http-request';
    import { createResponse } from 'create-response';
    import URLSearchParams from 'url-search-params';
    export async function responseProvider(request) {
    
      let jsonresponse = await httpRequest('/xyz/menujson.json');
      let menujson = await jsonresponse.json();
    
      let rewriter = new HtmlRewritingStream();
    
      rewriter.onElement('section', el => {
        el.before(`

    ${menujson[0].name}

    `); el.after(`

    ${menujson[0].items[3].item}

    ${menujson[0].items[3].price}

    `); el.prepend(`

    ${menujson[0].items[2].item}

    ${menujson[0].items[2].price}

    `); el.append(`

    ${menujson[0].items[1].item}

    ${menujson[0].items[1].price}

    `); el.replaceChildren(`

    ${menujson[0].items[0].item}

    ${menujson[0].items[0].price}

    `); }); if(getLoggedInUser(request)){ rewriter.onElement('h1', el => { el.after('

    Special 20% discount member offer applied!

    '); }); } let subrequestHeaders = {"X-Subrequest": ["true"]}; let htmlResponse = await httpRequest("/xyz/template.html", {headers: subrequestHeaders}); if (!htmlResponse.ok) { return createResponse(500, {}, `Failed to fetch doc: ${htmlResponse.status}`); } return createResponse(200, {}, htmlResponse.body.pipeThrough(rewriter)); } function getLoggedInUser(request){ //Your logic which could return boolean value. }

    Conference/Meeting Details using EdgeWorkers

    This example implements a Conference Attendance Code API call that returns the meeting details of a conference as HTML if the user provides the correct code (if you did this in the browser it would defeat the confidentiality purpose).

    Outcome :

    With abc123 in the key GET parameter, the user is shown conference details, without going all the way to origin, but by replacing values of key, you get an error instead, keeping the information away from the browser.

  • View this example on Github
  • import URLSearchParams from 'url-search-params';
    
    export function onClientRequest(request) {
        var params = new URLSearchParams(request.query);
        if (params.get('key') === 'abc123') {
            request.respondWith(200, {
                    'Content-Type': ['text/html']
                },
                'Welcome to the conference.Here are the venue details:123 Main Street, San Francisco, CADec, 6th 2019 10pm sharp');
        } else {
            request.respondWith(200, {
                    'Content-Type': ['text/html']
                },
                'You have entered an incorrect code.');
        }
    }

    Simple API Orchestration Response using EdgeWorkers

    This example demonstrates how EdgeWorkers can be used to merge multiple internal APIs into a single API response from a user experience perspective.

    Outcome :

    Merged multiple internal APIs into a single API response.

  • View this example on Github
  • import { httpRequest } from 'http-request';
    import { createResponse } from 'create-response';
    
    const endPoint1 = '/api/example/endpoint1';
    const endPoint2 = '/api/example/endpoint2';
    const endPoint3 = '/api/example/endpoint3';
    
    async function getJSON(url) {
        const response = await httpRequest(`${url}`);
        if (response.ok) {
            return await response.json();
        } else {
            return {
                error: `Failed to return ${url}`
            };
        }
    }
    
    // The responseProvide function generates a response, acting as a "surrogate origin".
    // The response may be cached according to the caching rules configured in the property.
    export async function responseProvider(request) {
        const result = {};
    
        // Make all requests in parallel to retrieve content.
        const endPointResult1 = getJSON(endPoint1).then(json => {
            result.endPoint1 = json;
        });
        const endPointResult2 = getJSON(endPoint2).then(json => {
            result.endPoint2 = json;
        });
        const endPointResult3 = getJSON(endPoint3).then(json => {
            result.endPoint3 = json;
        });
    
        // Wait for all requests to complete.
        await Promise.all([endPointResult1, endPointResult2, endPointResult3]);
    
        // Return merged JSON as the response.
        return Promise.resolve(createResponse(
            200, {
                'Content-Type': ['application/json']
            },
            JSON.stringify(result)
        ));
    }

    Traffic Allow list of users

    This example implements an allow list depending on the geographic locale of the end user. If user is arriving from United States embargoed countries, a 403 deny will occur.

    Outcome :

    If user is arriving from United States embargoed countries, a 403 deny will occur else Hello from EdgeWorkers.

  • View this example on Github
  • // List of currently US embargoed countries, plus N/A indicating no country data found (rare, if any)
    const embargoedCountries = ['IR', 'KP', 'SY', 'SD', 'CU', 'VE', 'N/A'];
    
    export function onClientRequest(request) {
        // Collect the end user's country based on Akamai EdgeScape data
        const country = (request.userLocation.country) ? request.userLocation.country : 'N/A';
    
        // Check if end user's country is in embargo list
        const embargoed = embargoedCountries.includes(country);
    
        // Provide appropriate messaging based on embargo status
        if (!embargoed) {
            request.respondWith(200, {
                    'Content-Type': ['text/html;charset=utf-8']
                },
                'Hello ' + country + ' from Akamai EdgeWorkers!');
        } else {
            request.respondWith(403, {
                    'Content-Type': ['text/html;charset=utf-8']
                },
                'Sorry, users from ' + country + ' may not view this content', 'EW-embargo');
        }
    }

    GET SET Cookie using Edge Workers

    This example implements an EdgeWorker that will respond with welcome message if its saved in cookie else will ask the user to enter their name.

    Outcome :

    Return reponse with username if it exists in cookie.

  • View this example on Github
  • import { Cookies, SetCookie } from 'cookies';
    
    		 export function onClientRequest (request) {
    		   const cookies = new Cookies(request.getHeader('Cookie'));
    		   var cartCookie = cookies.get('cart');
    
    		   if (!cartCookie) {
    		     request.respondWith(200, { 'Content-Type': ['application/json; charset=utf-8'] }, '{}');
    		   }
    		 }

    Error handling using EdgeWorkers

    This example translates a HTTP 503 status code (service unavailable) coming from an overloaded origin into a HTML page presenting the information in a more user friendly way. It also includes javascript to retry after the period indicated by the 'Retry-After' header coming from origin, if present. Otherwise it'll retry after a default number of seconds. Note that even if the content from origin is dynamic it makes sense to configure the property such that the HTTP error responses are cached at least for a short duration.

    Outcome :

    Page Displaying error handling.

  • View this example on Github
  • /*
    onOriginResponse: This event happens as the origin response is created.
    The event only happens if the response is not served from cache and not constructed on the edge.
    Use this event if you want to modify the response before it is cached.
    */
    export function onOriginResponse(request, response) {
        response.addHeader('Origin-Response-Status', response.status);
    
        if (response.status === 503 || response.status === 500) {
            var retry = parseInt(response.getHeader('Retry-After')) || 10;
            request.respondWith(200, {
                    'Content-Type': ['text/html']
                }, ' setTimeout(function () 
                //{ window.location.href="' + escape(request.path) + '"; }, ' + retry + '*1000); 
                The origin server is currently overloaded, please retry in ' + retry + '
                seconds ');
            }
        }

    Find Replace Stream using EdgeWorkers

    This example demonstrates how an EdgeWorker can be used to modify an HTTP response stream by performing a find & replace operation on the response. The example will search for a specific text, and replace it with another, across the entire response body. It receives an optional parameter to specify how many times a replement must be performed. If not specified, the replacement will take place as many times as possible. The demo will replace stream: "This is the original string" to "This is the updated string".

    Outcome :

    Page demostrating find replace stream using EdgeWorkers.

  • View this example on Github
  • import { ReadableStream,WritableStream } from 'streams';
    import { httpRequest } from 'http-request';
    import { createResponse } from 'create-response';
    import { TextEncoderStream,TextDecoderStream } from 'text-encode-transform';
    import { FindAndReplaceStream } from 'find-replace-stream.js';
    import { logger } from 'log';
    
    export function responseProvider(request) {
        // Get text to be searched for and new replacement text from Property Manager variables in the request object.
        // const tosearchfor = request.getVariable('PMUSER_EWSEARCH');
        // const newtext = request.getVariable('PMUSER_EWNEWTEXT');
        // Set to 0 to replace all, otherwise a number larger than 0 to limit replacements
        const tosearchfor = 'This is the original string';
        var newtext = 'This is the updated string';
        const howManyReplacements = 1;
    
        return httpRequest(`${request.scheme}://${request.host}${request.url}`).then(response => {
            return createResponse(
                response.status,
                response.headers,
                response.body.pipeThrough(new TextDecoderStream())
                .pipeThrough(new FindAndReplaceStream(tosearchfor, newtext, howManyReplacements))
                .pipeThrough(new TextEncoderStream())
            );
        });
    }

    Response Manipulation Stream using EdgeWorkers

    This example demonstrates how an EdgeWorker can be used to modify an HTML response stream by adding content to the response. The example will add a script to the page just before the closing head tag.

    Outcome :

    Page demonstrating Response Manipulation Stream using EdgeWorkers.

  • View this example on Github
  • import { ReadableStream, WritableStream } from 'streams';
    import { httpRequest } from 'http-request';
    import { createResponse } from 'create-response';
    import { TextEncoderStream, TextDecoderStream } from 'text-encode-transform';
    
    class HTMLStream {
        constructor() {
            let readController = null;
            this.readable = new ReadableStream({
                start(controller) {
                    readController = controller;
                }
            });
    
            async function handleTemplate(text) {
                const startIndex = text.indexOf(tag);
                if (startIndex === -1) {
                    readController.enqueue(text);
                } else {
                    readController.enqueue(text.substring(0, startIndex));
                    readController.enqueue(script);
                    readController.enqueue(text.substring(startIndex));
                }
            }
    
            let completeProcessing = Promise.resolve();
    
            this.writable = new WritableStream({
                write(text) {
                    completeProcessing = handleTemplate(text, 0);
                },
                close(controller) {
                    completeProcessing.then(() => readController.close());
                }
            });
        }
    }
    
    export function responseProvider(request) {
        return httpRequest(`${request.scheme}://${request.host}${request.url}`).then(response => {
    
            // Get headers from response
            let headers = response.getHeaders();
            // Remove content-encoding header.  The response stream from EdgeWorkers is not encoded.
            // If original response contains `Content-Encoding: gzip`, 
            then the Content - Encoding header does not match the actual encoding.
            delete headers["content-encoding"];
            // Remove `Content-Length` header.  Modifying HTML is likely to change the content length.
            // Leaving the Length of the original content would be incorrect.
            delete headers["content-length"];
    
            return createResponse(
                response.status,
                headers,
                response.body.pipeThrough(new TextDecoderStream())
                .pipeThrough(new HTMLStream())
                .pipeThrough(new TextEncoderStream())
            );
        });
    }

    Add geoLocation cookie using EdgeWorkers

    This example implements an EdgeWorker to add a geolocation data to a cookie in the HTTP response. This cookie returns location information about the client where the request originates, including a lookup from custom data.

    Outcome :

    Page demostrating add geoLocation cookie using EdgeWorkers.

  • View this example on Github
  • // Import cookies library to provide helper functions
    import { SetCookie } from 'cookies';
    import { salesRegions } from 'data.js';
    
    // Helper function to find a sales region by state.
    function findRegionByState(state) {
        return salesRegions.find((region) => region.states.includes(state));
    }
    
    // Add cookie in the outgoing response to the browser
    export function onClientResponse(request, response) {
        // Retrieve user location from the request object
        const userLocation = request.userLocation;
    
        // Extract country, region (e.g., U.S. state), and city from userLocation
        const country = userLocation.country || 'N/A';
        const region = userLocation.region || 'N/A';
        const city = userLocation.city || 'N/A';
        const salesRegion = findRegionByState(region);
    
        // Create a cookie, with location fields separate by '+'
        const locationCookieValue = `${country}+${region}+${city}`;
    
        // Create cookie with an expiration of 1 day (86,400 seconds)
        var cookie = new SetCookie({
            name: 'location',
            value: locationCookieValue,
            path: '/',
            maxAge: 86400
        });
    
        // Add cookie header to outgoing  response
        response.addHeader('Set-Cookie', cookie.toHeader());
    
        //  If sales region is found, then also add the salesRegion cookie
        if (salesRegion) {
            const regionDataCookieValue = `${salesRegion.name}:${salesRegion.population}`;
            var salesRegionCookie = new SetCookie({
                name: 'salesRegion',
                value: regionDataCookieValue,
                path: '/',
                maxAge: 86400
            });
            response.addHeader('Set-Cookie', salesRegionCookie.toHeader());
        }
    }

    Modify the forward origin path based on device type using EdgeWorkers.

    This example implements modification of the forward origin path of the url to return device specific content.

    Outcome :

    Page demostrating forward origin path based on device type using EdgeWorkers.

  • View this example on Github
  • export function onClientRequest(request) {
        if (request.device.isMobile) {
            request.route({
                path: '/mobile' + request.path
            });
        } else if (request.device.isTablet) {
            request.route({
                path: '/tablet' + request.path
            });
        }
    }

    Cachekey Device Type using EdgeWorkers

    This example includes the device type (tablet or mobile) from a PMUSER variable in the computed cache key for an Edge Server.

    Outcome :

    Page demostrating Cachekey Device Type using EdgeWorkers.

  • View this example on Github
  • export function onClientRequest(request) {
        request.setVariable('PMUSER_DEVICETYPE', 'Desktop');
        if (request.device.isMobile) {
            request.setVariable('PMUSER_DEVICETYPE', 'Mobile');
        } else if (request.device.isTablet) {
            request.setVariable('PMUSER_DEVICETYPE', 'Tablet');
        }
        request.cacheKey.includeVariable('PMUSER_DEVICETYPE');
    }

    Locate two nearest stores using Edge Workers

    This example implements a microservice store locator API call that returns the two stores nearest to the provided latitude and longitude.

    Note : Latitude and Longitude values are hardcode for demo purpose.

    Outcome :

    Locate two nearest stores provided by latitude and longitude using Edge Workers.

  • View this example on Github
  • import URLSearchParams from 'url-search-params';
    
    		 import KDBush from 'kdbush';
    		 import geokdbush from 'geokdbush';
    
    		 import locations from './data/locations.json';
    
    		 // Initialize index of locations
    		 const indexedLocations = new KDBush(locations.elements, (p) => p.lon, (p) => p.lat);
    
    		 export function onClientRequest (request) {
    		   // Extract longitude and latitude from query string
    		   const params = new URLSearchParams(request.query);
    		   const lat = Number(params.get('lat'));
    		   const lon = Number(params.get('lon'));
    
    		   // Respond with an error if lat or lon are not passed in.
    		   if (!lon || !lat) {
    		     request.respondWith(
    		       400,
    		       { 'Content-Type': ['application/json;charset=utf-8'] },
    		       JSON.stringify({ error: 'lat and lon parameters must be provided' })
    		     );
    		     return;
    		   }
    
    		   if (!nearest) {
    		     request.respondWith(
    		       400,
    		       { 'Content-Type': ['application/json;charset=utf-8'] },
    		       JSON.stringify({ error: `Error locating nearby locations. lat:${lat}, lon:${lon}` })
    		     );
    		     return;
    		   }
    
    		   const result = [];
    		   for (var i = 0; i < nearest.length; i++) {
    		     const location = nearest[i];
    		     // calulate distance and convert to miles
    		     const distance = geokdbush.distance(lon, lat, location.lon, location.lat) / 1.609;
    		     // add distance and location to the result
    		     result.push({ distance: distance, location: location });
    		   }
    
    		   // Respond with json result containing nearest locations
    		   request.respondWith(
    		     200,
    		     { 'Content-Type': ['application/json;charset=utf-8'] },
    		     JSON.stringify(result, null, 2));
    		 }

    Find popular search terms using EdgeWorkers

    This EdgeWorker serves responses for popular search terms at the Edge. Autocomplete requests are typically long tail and frequently changing. Without an EdgeWorker it is difficult to get up to date content from cache. Storing and serving the most popular search terms from the Edge will speed up responses significantly.

    Outcome :

    Shows popular search terms using EdgeWorkers.

  • View this example on Github
  • import URLSearchParams from 'url-search-params';
    import { default as searchterms } from './searchterms.js';
    
    export function onClientRequest(request) {
        const params = new URLSearchParams(request.query);
        const jsonContentType = {
            'Content-Type': ['application/json;charset=utf-8']
        };
        const searchResult = searchterms[params.get('term').toLowerCase()];
        if (searchResult) {
            request.respondWith(200, jsonContentType, JSON.stringify(searchResult));
        }
    }

    Wrap JSON response with dynamic unique callback using EdgeWorkers

    This example demonstrates how an EdgeWorker can be used to wrap JSON response with dynamic unique callback function leveraging Response Provider and Stream API for efficient content transformation. The EW should be enabled on JSON requests containing callback query parameter. This can easily be accomplished with match on file extension and query parameter match in Property Manager. When such request comes in, this EW removes the callback query param and makes a sub-request to fetch the JSON data, serving it as a stream. EW code adds prefix with callback function name captured from the query param and suffix. Both JSON data and transformed data can be cached and this can be achieved with standard "Caching" behavior in Property Manager (if caching is allowed in your use-case).

    Outcome :

    Add callback as callback=someFunctionName

  • View this example on Github
  • import { TransformStream } from "streams";
    import { httpRequest } from "http-request";
    import { createResponse } from "create-response";
    import URLSearchParams from "url-search-params";
    
    function str2uint8arr(s) {
        return Uint8Array.from(Array.from(s, (x) => x.charCodeAt(0)))
    }
    
    export function responseProvider(request) {
        let params = new URLSearchParams(request.query);
        let callbackName = params.get("callback");
        params.delete("callback");
    
        const jsonpTransformer = new TransformStream({
            transform(chunk, controller) {
                if (chunk) {
                    controller.enqueue(chunk);
                }
            },
            start(controller) {
                controller.enqueue(str2uint8arr(callbackName + "("));
            },
            flush(controller) {
                controller.enqueue(str2uint8arr(")"));
            }
        });
    
        const options = {
            'headers': {
                'Accept': 'application/json'
            }
        };
        return httpRequest(`${request.scheme}:
    		 	//${request.host}${request.path}?${params.toString()}`, options).then((response) => {
    
            // Get headers from response
            let headers = response.getHeaders();
            // Remove content-encoding header.  The response stream from EdgeWorkers is not encoded.
            // If original response contains `Content-Encoding: gzip`, 
            then the Content - Encoding header does not match the actual encoding.
            delete headers["content-encoding"];
            // Remove `Content-Length` header.  Modifying JSON is likely to change the content length.
            // Leaving the Length of the original content would be incorrect.
            delete headers["content-length"];
    
            return createResponse(
                response.status,
                headers,
                response.body.pipeThrough(jsonpTransformer)
            );
        });
    }

    Randomly assign a new user to a group for A/B testing using EdgeWorkers

    This example will randomly assign a new user to a group for A/B testing. The assignment will be stored in a cookie and will be passed to the origin in a query parameter. To allow easy testing, the A/B group can be forced via a query string parameter. The group names, percentage split, cookie name, and query parameter name are configured through constants in the EdgeWorker JavaScript module.

    Outcome :

    Randomly assign a new user to a group for A/B testing.

  • View this example on Github
  • import { Cookies,SetCookie } from 'cookies';
    import URLSearchParams from 'url-search-params';
    
    // ====== Begin Configuration ====== //
    // Update constants below to configure A/B logic
    
    /** Probability that a user is added to the "A" group.  0.5 = 50% */
    const probabilityOfA = 0.5;
    
    /** Name of cookie that stores A/B group assignment. */
    const cookieName = 'testGroup';
    
    /**
     * Name of query parameter that contains A/B group assignment
     * This query parameter will be added to the outgoing onClientRequest.
     * The query parameter can be added to the incoming request to force A/B group assignment.
     */
    const queryParamName = 'testGroup';
    
    /** Cookie and query string value to use for users in the "A" group. */
    const groupAValue = 'A';
    
    /** Cookie and query string value to use for users in the "B" group. */
    const groupBValue = 'B';
    
    // ====== End Configuration ====== //
    
    export function onClientRequest(request) {
        const cookies = new Cookies(request.getHeader('Cookie'));
        const params = new URLSearchParams(request.query);
    
        // Initialize existing and reult group value from the request cookie
        const existingGroupValue = cookies.get(cookieName);
        let resultGroupValue = existingGroupValue;
    
        // override result group value if forced by query parameter
        const paramValue = params.get(queryParamName);
        if (paramValue) {
            resultGroupValue = paramValue;
        }
    
        // If no group value has been assigned,
        // then randomly choose one based on configured percentage
        if (!resultGroupValue) {
            if (Math.random() <= probabilityOfA) {
                resultGroupValue = groupAValue;
            } else {
                resultGroupValue = groupBValue;
            }
        }
    
        // If group value if different than the existing cookie,
        // then replace the incoming cookie with the new value.
        if (resultGroupValue != existingGroupValue) {
            cookies.delete(cookieName);
            cookies.add(cookieName, resultGroupValue);
            request.setHeader('Cookie', cookies.toHeader());
        }
    
        // If the group was not already included in the incoming query parameter,
        // then add the query parameter to the query string.
        // The query parameter allows the origin to respond with appropriate logic
        // and ensures the A/B group is included in the cache key.
        if (!paramValue) {
            params.append(queryParamName, resultGroupValue);
            request.route({
                query: params.toString()
            });
        }
    }
    
    export function onClientResponse(request, response) {
        // Set a response cookie with the A/B group based on
        // the request cookie  set in the onClientRequest handler.
        const cookies = new Cookies(request.getHeader('Cookie'));
        const cookieValue = cookies.get(cookieName);
        const setCookie = new SetCookie({
            name: cookieName,
            value: cookieValue
        });
        response.setHeader('Set-Cookie', setCookie.toHeader());
    }

    Enable multivariate testing and multiple tests are executed simultaneously using EdgeWorkers

    This example will enable multivariate testing. Multiple tests are executed simultaneously. A single variant is selected for each test. Variants will be randomly assigned to a new user, with each selected variant stored in a cookie. Each variant will also be passed to the origin in a query string parameter. The probability of choosing each variant can be configured by adjusting the weight of each variant. To allow easy testing, the variant can be forced via a query string parameter. Custom actions to be executed in the request and/or response phase of each variant. For example, a custom action can be used to route a variant to a different origin or to construct a response at the edge.

    Outcome :

    Enable multivariate testing.

  • View this example on Github
  • import { Cookies, SetCookie} from 'cookies';
    import URLSearchParams from 'url-search-params';
    
    // ====== Begin Configuration ====== //
    
    const groups = [{
            // "test1" is a simple test that chooses between 2 variants with a 50/50 split
            // The chosen variant will be included in both:
            //   * a query string parameter that is sent to the origin a
            //   * a cookie that is sent to the browser
            testName: 'test1',
            cookieName: 'test1',
            queryParamName: 'test1',
            variants: [{
                    variantName: '1a'
                },
                {
                    variantName: '1b'
                }
            ]
        },
        {
            // "test2" is a more complex test that chooses between 3 variants
            // variants "2b" and "2c" are twice as likely to be selected as "2a"
            //  Custom request actions are used to
            //  * route to a different origin in variants "2a" and "2b"
            //  * construct a response at the Edge in variant "2c"
            // Custom response actions are used to add a response header in each variant
            testName: 'test2',
            cookieName: 'test2',
            queryParamName: 'test2',
            variants: [{
                    variantName: '2a',
                    weight: 1,
                    requestAction(request) {
                        request.route({
                            origin: 'microservice1'
                        });
                    },
                    responseAction(request, response) {
                        response.addHeader('X-Variant', '2a');
                    }
                },
                {
                    variantName: '2b',
                    weight: 2,
                    requestAction(request) {
                        request.route({
                            origin: 'microservice2'
                        });
                    },
                    responseAction(request, response) {
                        response.addHeader('X-Variant', '2b');
                    }
                },
                {
                    variantName: '2c',
                    weight: 2,
                    requestAction(request) {
                        request.respondWith(
                            200, {
                                'Content-Type': ['application/json']
                            },
                            JSON.stringify({
                                heroImageUrl: '/assets/images/hero2c.jpg',
                                text: 'This is variant 2c, generated from an Akamai EdgeWorker'
                            }));
                    },
                    responseAction(request, response) {
                        response.addHeader('X-Variant', '2c');
                    }
                }
            ]
        }
    ];
    
    // ====== End Configuration ====== //
    
    /**
     * Process each test group to convert "weights" into a "range".
     * The range will be between 0-1, with the upper bound stored in each group.
     * This facilitates selection via Math.random()
     */
    function processGroups() {
        groups.forEach((group) => {
            const sumOfWeights = group.variants.reduce((currValue, variant) =>
                currValue + (variant.weight || 1),
                0
            );
    
            let upperBound = 0;
            group.variants.forEach((variant) => {
                upperBound += (variant.weight || 1) / sumOfWeights;
                variant.upperBound = upperBound;
            });
        });
    }
    
    processGroups(groups);
    
    export function onClientRequest(request) {
        const cookies = new Cookies(request.getHeader('Cookie'));
        const params = new URLSearchParams(request.query);
    
        groups.forEach((group) => {
            const cookieName = group.cookieName;
            const queryParamName = group.queryParamName;
    
            let resultVariant;
    
            // Initialize existing and reult variant value from the request cookie
            const existingVariantName = cookies.get(cookieName);
    
            // override result variant if forced by query parameter
            const paramValue = params.get(queryParamName);
            if (paramValue) {
                resultVariant = group.variants.find((variant) => variant.variantName === paramValue);
            }
    
            // if not overriden by query prameter, locate variant in cookie
            if (existingVariantName && !resultVariant) {
                resultVariant = group.variants.find((variant) => variant.variantName === existingVariantName);
            }
    
            // If no variant has been assigned,
            // then randomly choose one based on configured percentage
            if (!resultVariant) {
                const randomNumber = Math.random();
                resultVariant = group.variants.find((variant) => variant.upperBound > randomNumber);
            }
    
            // If variant if different than the existing cookie,
            // then replace the incoming cookie with the new value.
            if (resultVariant.variantName !== existingVariantName) {
                cookies.delete(cookieName);
                cookies.add(cookieName, resultVariant.variantName);
                request.setHeader('Cookie', cookies.toHeader());
            }
    
            // If the group was not already included in the incoming query parameter,
            // then add the query parameter to the query string.
            // The query parameter allows the origin to respond with appropriate logic
            // and ensures the A/B group is included in the cache key.
            if (!paramValue) {
                params.append(queryParamName, resultVariant.variantName);
                request.route({
                    query: params.toString()
                });
            }
    
            // Call the requestAction function, if it exists on the variant.
            if (resultVariant.requestAction) {
                resultVariant.requestAction(request);
            }
        });
    }
    
    export function onClientResponse(request, response) {
        const cookies = new Cookies(request.getHeader('Cookie'));
    
        groups.forEach((group) => {
            const cookieName = group.cookieName;
            // Set a response cookie with the A/B group based on
            // the request cookie  set in the onClientRequest handler.
            const cookieValue = cookies.get(cookieName);
            const setCookie = new SetCookie({
                name: cookieName,
                value: cookieValue,
                path: '/'
            });
            response.addHeader('Set-Cookie', setCookie.toHeader());
    
            // Call the responseAction function, if it exists on the variant.
            const variant = group.variants.find((variant) => variant.variantName == cookieValue);
            if (variant.responseAction) {
                variant.responseAction(request, response);
            }
        });
    }

    Redirect visitors based on Geo locations using EdgeWorkers

    EdgeWorker example to redirect visitors based on the location of the request to present location relevant pages.

    Outcome :

    Redirect visitors based on Geo locations.

  • View this example on Github
  • // define country top level domain mapping
    const tldMap = {
        CA: '.ca',
        GB: '.co.uk',
        US: '.com'
    };
    
    export function onClientRequest(request) {
        // Break out sub domain from host
        const subDomain = request.host.split('.')[0];
    
        // Break out domain from host
        const domain = request.host.split('.')[1];
    
        // determine top level domain based on request origin country
        let tld = tldMap[request.userLocation.country];
    
        // if top level domain is supported default to .com
        if (tld === undefined) {
            tld = '.com';
        }
    
        // built up new domain
        const redirectDomain = subDomain + '.' + domain + tld;
    
        // check incoming host different against built up host
        if (request.host !== redirectDomain) {
            // redirect to new host
            request.respondWith(302, {
                Location: [request.scheme + '://' + redirectDomain + request.url]
            }, '');
        }
    }

    EdgeKV Hello World Example

    The Hello World example demonstrates how you can use EdgeWorkers and EdgeKV to implement a simple Dynamic Content Assembly use case whereby the html response is dynamically constructed on the edge based on the content of the Accept-Language header in the client request. It also shows how you could use getText() helper method.

    Outcome :

    Page Displaying Hello World from Edge Workers using EdgeKV.

  • View this example on Github
  • /*
    (c) Copyright 2020 Akamai Technologies, Inc. Licensed under Apache 2 license.
    
    Version: 1.0.0
    
    Purpose:
      Implements a simple "Hello World" Dynamic Content Assembly EW whereby the 
      response is dynamically constructed based on the Accept-Language header 
      in the request.
      For simplicity, the 1st Accept-Language header encountered is used as key
      to retrieve the corresponding language specific greeting from EdgeKV.
      */
    import { createResponse } from 'create-response';
    import { EdgeKV } from './edgekv.js';
    
    // Create simple Hello World Response based on request Accept-Language
    async function hello_world_response(request) {
    
        // Defaults to use if item not in EdgeKV
        let default_greeting = "Hello World";
        let language = "en";
        let content_lang = "en-US";
        let greeting = "";
        let err_msg = ""
    
        // Retrieve Accept-Language header & extract language key
        let languages = request.getHeader('Accept-Language');
        if (languages && languages[0]) {
            content_lang = languages[0].split(',')[0];
            language = content_lang.split('-')[0];
        }
        let key = language.toLowerCase();
    
        // Set Up EdgeKV
        const edgeKv = new EdgeKV({
            namespace: "default",
            group: "greetings"
        });
    
        // Retrieve the greeting associated with the language using the latter 
        // as key. We use a default greeting if the item is not found.
        try {
            greeting = await edgeKv.getText({
                item: key,
                default_value: default_greeting
            });
        } catch (error) {
            // Catch the error and store the error message to use in a response
            // header for debugging. Use a default greeting as well in this case.
            err_msg = error.toString();
            greeting = default_greeting;
        }
    
        // We choose to always send back a 200 OK with a default greeting
        // and just log any errors in the 'X-EKV-ERROR' response header
        let response = {
            status: 200,
            headers: {
                'Content-Type': ['text/html'],
                'Content-Language': [content_lang],
                // Safely Encode the error message to remove unsafe chars
                // but also replace some encoded strings with safe chars for readability
                'X-EKV-ERROR': [encodeURI(err_msg).replace(/(%20|%0A|%7B|%22|%7D)/g, " ")]
            },
            body: html_body
        };
    
        // Send Response
        return createResponse(response.status,
            response.headers,
            response.body);
    }
    
    export async function responseProvider(request) {
        return hello_world_response(request)
    }

    EdgeKV Promo Code Validation Example

    The Promo Code Validation example demonstrates how you can use EdgeWorkers and EdgeKV to validate promo codes at the Edge. A list of promo codes with valid date ranges is stored in EdgeKV.It also shows how you could use getJson() helper method.

    Outcome :

    Validates the entered promo code

  • View this example on Github
  • import URLSearchParams from 'url-search-params';
    import { createResponse } from 'create-response';
    import { EdgeKV} from './lib/edgekv.js';
    
    function createErrorResponse(message) {
        return createResponse(
            400, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify({
                error: message
            })
        );
    }
    
    function createInvalidCodeResponse() {
        return createResponse(
            404, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify({
                error: 'Code is not valid'
            })
        );
    }
    
    function createValidCodeResponse(code) {
        return createResponse(
            200, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify(code)
        );
    }
    
    
    export async function responseProvider(request) {
        const now = Date.now() / 1000;
        const params = new URLSearchParams(request.query);
        const promocode = params.get('code');
    
        // Respond with an error if code is not passed in.
        if (!promocode) {
            return createErrorResponse('code parameter must be provided');
        }
    
        const edgeKv = new EdgeKV({
            namespace: "ecom",
            group: "promocodes"
        });
        try {
            // Lookup promo code from EdgeKV
            let promo = await edgeKv.getJson({
                item: promocode
            });
    
            if (!promo || promo.valid_from > now || promo.valid_to < now) {
                // Respond with an error if promo is not found
                // or promo is not valid for current date
                return createInvalidCodeResponse();
            }
    
            // Valid promo found
            return createValidCodeResponse(promo);
        } catch (error) {
            return createErrorResponse(error.toString());
        }
    }

    EdgeKV User Registration Example

    This example demonstrates how you can use EdgeWorkers and EdgeKV to collect user details.It also shows how you could use putJson() helper method.

    Outcome :

    Collects User details and prints unique code as acknowledgment.

    Note : Please copy the “key” value from the output if you wish to verify the entered details in the Search User example.

    import URLSearchParams from 'url-search-params';
    import { createResponse } from 'create-response';
    import { EdgeKV } from './edgekv.js';
    
    function createErrorResponse(message) {
        return createResponse(
            400, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify({
                error: message
            })
        );
    }
    
    function createInvalidCodeResponse() {
        return createResponse(
            404, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify({
                error: 'Code is not valid'
            })
        );
    }
    
    function createValidCodeResponse(code) {
        return createResponse(
            200, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify(code)
        );
    }
    
    
    export async function responseProvider(request) {
        const now = Date.now() / 1000;
        const params = new URLSearchParams(request.query);
        const name = params.get('name');
        const mobileNumber = Number(params.get('mobile_no'));
    
        var myJSON = JSON.stringify(params);
        // Respond with an error if lat or lon are not passed in.
        if (!name || !mobileNumber) {
            return createErrorResponse('All parameter must be provided');
        }
    
        const edgeKv = new EdgeKV({
            namespace: "ecom",
            group: "registration"
        });
        try {
    
            let reg = await edgeKv.putJson({
                item: now,
                value: myJSON
            });
            return createValidCodeResponse(reg);
        } catch (error) {
            return createErrorResponse(error.toString());
        }
    }

    EdgeKV Search User Details Example

    The example demonstrates how you can use EdgeWorkers and EdgeKV to search for specific user details. It also shows how you could use getJson() helper method.

    Note : This is an extension of User Registration use case. You would need the key value from the User Registration use case if you want to verify the details.

    Outcome :

    Demonstrates the use of getJson() EKV function.

    import URLSearchParams from 'url-search-params';
    import { createResponse } from 'create-response';
    import { EdgeKV } from './edgekv.js';
    
    function createErrorResponse(message) {
        return createResponse(
            400, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify({
                error: message
            })
        );
    }
    
    function createInvalidCodeResponse() {
        return createResponse(
            404, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify({
                error: 'Code is not valid'
            })
        );
    }
    
    function createValidCodeResponse(code) {
        return createResponse(
            200, {
                'Content-Type': ['application/json;charset=utf-8']
            },
            JSON.stringify(code)
        );
    }
    
    
    export async function responseProvider(request) {
    
        const params = new URLSearchParams(request.query);
        const userid = params.get('code');
    
        // Respond with an error if code is not passed in.
        if (!userid) {
            return createErrorResponse('user id parameter must be provided');
        }
    
        const edgeKv = new EdgeKV({
            namespace: "ecom",
            group: "registration"
        });
        try {
            // Lookup promo code from EdgeKV
            let promo = await edgeKv.getJson({
                item: userid
            });
    
            // Valid promo found
            return createValidCodeResponse(promo);
        } catch (error) {
            return createErrorResponse(error.toString());
        }
    }

    EdgeKV A/B Testing Example

    A/B testing is beneficial to the business to test new features and measure user engagement. But this often comes with the cost of impacting page performance and user experience.

    Outcome :

    By moving the A/B test to the Akamai edge we can cache multiple variants of the same page close to the user making the decision of which variant to serve to the user without making the long round-trip to the origin web server or relying on client-side javascript.

    Example EdgeKV data :

    {
        "forwardHeaderName": "X-AB-Variant",
        "variants": {
            "a": {
                "weight": 25
            },
            "b": {
                "weight": 25
            },
            "c": {
                "weight": 50
            }
        }
    }

    Below is the source code :

    import { Cookies, SetCookie } from 'cookies';
    import { logger } from 'log';
    import { EdgeKV } from './edgekv.js';
    
    // Initialize EdgeKV library
    const edgeKv_abpath = new EdgeKV({
        namespace: "default",
        group: "ab-data"
    });
    
    export async function onClientRequest(request) {
        // Read config data from EdgeKV
        let abConfig = await edgeKv_abpath.getJson({
            item: "ab-config"
        });
    
        // Check the ab-variant cookie to see if user has an existing variant assigned.
        let cookies = new Cookies(request.getHeader('Cookie'));
        let abVariant = cookies.get('ab-variant');
    
        // If there is no variant assigned, choose a variant at random,
        // based on the configuration data in EdgeKV
        if (!abVariant) {
            logger.log('choosing random variant');
            abVariant = getRandomVariant(abConfig)
        }
    
        // Add forward header to communicate the variant to the origin server
        request.addHeader(abConfig.forwardHeaderName, abConfig.variants[abVariant])
    
        // Add variant name to the cache key, enabling caching of multiple variants.
        request.setVariable('PMUSER_AB_VARIANT', abVariant);
        request.cacheKey.includeVariable('PMUSER_AB_VARIANT');
    
        // Log variant to debug headers for debugging purposes
        logger.log('Variant: %s', abVariant);
    }
    
    export function onClientResponse(request, response) {
        // Create or extend ab-variant cookie
        let variantId = request.getVariable('PMUSER_AB_VARIANT');
        if (variantId) {
            let expDate = new Date();
            expDate.setDate(expDate.getDate() + 7);
            let setBucketCookie = new SetCookie({
                name: "ab-variant",
                value: variantId,
                expires: expDate
            });
            response.addHeader('Set-Cookie', setBucketCookie.toHeader());
        }
    }
    
    // Select random variante, using a weighted selection based on A/B config data.
    function getRandomVariant(abConfig) {
        let variantsArr = [];
        let cumulativeWeight = 0;
        for (let variantId in abConfig.variants) {
            let variant = abConfig.variants[variantId];
            cumulativeWeight += variant.weight;
            variantsArr.push({
                id: variantId,
                cumulativeWeight: cumulativeWeight
            });
        }
        var random = Math.random() * cumulativeWeight;
        let chosenVariant;
        for (let weightedVariant of variantsArr) {
            if (random < weightedVariant.cumulativeWeight) {
                chosenVariant = weightedVariant.id;
                break;
            }
        }
        return chosenVariant;
    
    }

    EdgeKV Product URL Redirects

    Redirects are often more complicated than: "Send traffic to this URL over to this other URL." You often need business logic to make routing decisions for site migrations, promotional campaigns, and loyalty programs.

    For example: Let’s assume the old site used a product sku in product-related URLs, but a revamped, new site uses a “tag” for SEO purposes.

    Old url: www.example.com/sku/{product_sku}/*

    New url: www.example.com/products/{product_tag}/*

    E.g., sku is 483D5F; tag denotes straight-fit-denim-jeans

    Old “reviews” url: www.example.com/sku/483D5F/reviews

    New “reviews” url: www.example.com/products/straight-fit-denim-jeans/reviews

    Outcome :

    Note the URL path changing from /sku/483D5F/reviews to products/straight-fit-denim-jeans/reviews

    This example uses EdgeWorkers + EdgeKV to extract a query string product SKU from an incoming URL, match it against a SKU stored in a KV database, and properly redirect the browser to the new product page.

    EKV Data: (key == 483D5F)

    {
       "sku": "483D5F",
       "tag": "straight-fit-denim-jeans"
    }
    

    Below is the source code :

    import { EdgeKV } from './edgekv.js';
    
    // Initialize EdgeKV library
    const edgeKv_products = new EdgeKV({
        namespace: "default",
        group: "products"
    });
    
    // Regex to match URL
    const URL_REGEX = /\/sku\/(?[a-zA-Z0-9]+)\/(?.*)/;
    
    
    export async function onClientRequest(request) {
        let regexMatch = request.url.match(URL_REGEX);
    
        // If regex matches URL, generate redirect
        if (regexMatch) {
            let sku = regexMatch.groups.sku;
    
            // Load product data from EdgeKV
            let productData = await edgeKv_products.getJson({
                item: sku
            });
            if (productData) {
                //Construct new URL, using product tag stored in EdgeKV
                let newUrl = `/products/${productData.tag}/${regexMatch.groups.suffix}`
    
                //Respond with 301 redirect
                request.respondWith(301, {
                    location: [newUrl]
                }, "");
            }
        }
    }

    Edge Compute Solutions

    Innovate in real time with the world’s largest serverless compute platform, Akamai puts your code closer to your users.

    EdgeWorkers

    EdgeWorkers enables developers to create and deploy microservices across more than a quarter of a million edge servers deployed around the globe. When development teams activate code at the edge, they push data, insights, and logic closer to their end users.

    EdgeWorkers helps your organization achieve high performance, customer-focused experiences without creating new challenges to your internal infrastructure or increased traffic at origin.

    EdgeKV

    Supercharge your EdgeWorkers apps with a serverless key-value store.

    EdgeKV is a key-value store database at the edge. It enables you to build data-driven EdgeWorker applications that require fast, frequent reads and infrequent writes.

    Version 2.0.2

    We'd love to hear from you! Please email us your feedback/ideas/bugs/issues to: dl-ECLIVE@akamai.com

    Ask Us On Slack! If you have a question about EdgeWorkers or simply want to say hello 👋 you're welcome to join us on our EdgeWorkers slack space.

    This website is Powered by Linode updated logo