Template Gallery

These templates are simple building blocks for developing Workers scripts.

Boilerplates

Skeletons that are useful when starting a project. Requires installation of Wrangler.

Hello World

Simple Hello World in JS

Paste this into your terminal:

Hello World Rust

Simple Hello World in Rust

Paste this into your terminal:

Router

Selects the logic based on the request method and URL. Use with REST APIs or apps that require routing logic.

Paste this into your terminal:

Static

Generates a fully functioning HTML page from raw HTML or sends raw JSON defined within your script.

Paste this into your terminal:

Hello World TypeScript

Simple Hello World in TypeScript

Paste this into your terminal:

Apollo GraphQL Server

🔥Lightning-fast, globally distributed Apollo GraphQL server, deployed at the edge using Cloudflare Workers. Read the tutorial to learn more!

Paste this into your terminal:

Emscripten + Wasm Image Resizer

Image Resizer in C compiled to Wasm with Emscripten

Paste this into your terminal:

Snippets

Copy pasteable code that can be used in a new or existing project.

Aggregate Requests

Sends two GET request to two urls and aggregates the responses into one response.

Copy into a Worker script:
async function handleRequest(request) { const init = { headers: { 'content-type': type, }, } const responses = await Promise.all([fetch(url1, init), fetch(url2, init)]) const results = await Promise.all([gatherResponse(responses[0]), gatherResponse(responses[1])]) return new Response(results, init) } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) }) /** * gatherResponse awaits and returns a response body as a string. * Use await gatherResponse(..) in an async function to get the response body * @param {Response} response */ async function gatherResponse(response) { const { headers } = response const contentType = headers.get('content-type') if (contentType.includes('application/json')) { return await response.json() } else if (contentType.includes('application/text')) { return await response.text() } else if (contentType.includes('text/html')) { return await response.text() } else { return await response.text() } } /** * Example someHost is set up to return JSON responses * Replace url1 and url2 with the hosts you wish to * send requests to * @param {string} url the URL to send the request to */ const someHost = 'https://workers-tooling.cf/demos' const url1 = someHost + '/requests/json' const url2 = someHost + '/requests/json' const type = 'application/json;charset=UTF-8'

Bulk Redirects

Redirects requests to certain URLs based a mapped object to the request’s URL.

Copy into a Worker script:
async function handleRequest(request) { let requestURL = new URL(request.url) let path = requestURL.pathname.split('/redirect')[1] let location = redirectMap.get(path) if (location) { return Response.redirect(location, 301) } // If in map, return the original request return fetch(request) } addEventListener('fetch', async event => { event.respondWith(handleRequest(event.request)) }) const externalHostname = 'workers-tooling.cf' const redirectMap = new Map([ ['/bulk1', 'https://' + externalHostname + '/redirect2'], ['/bulk2', 'https://' + externalHostname + '/redirect3'], ['/bulk3', 'https://' + externalHostname + '/redirect4'], ['/bulk4', 'https://google.com'], ])

Cache API

Cache using Cloudflare’s Cache API. This example can cache POST requests as well as change what hostname to store a response in cache. Note the previewer is not avalible for using Cache API.

Copy into a Worker script:
async function handleRequest(event) { let request = event.request let cacheUrl = new URL(request.url) // hostname for a different zone cacheUrl.hostname = someOtherHostname let cacheKey = new Request(cacheUrl, request) let cache = caches.default // Get this request from this zone's cache let response = await cache.match(cacheKey) if (!response) { //if not in cache, grab it from the origin response = await fetch(request) // must use Response constructor to inherit all of response's fields response = new Response(response.body, response) // Cache API respects Cache-Control headers, so by setting max-age to 10 // the response will only live in cache for max of 10 seconds response.headers.append('Cache-Control', 'max-age=10') // store the fetched response as cacheKey // use waitUntil so computational expensive tasks don't delay the response event.waitUntil(cache.put(cacheKey, response.clone())) } return response } async function handlePostRequest(event) { let request = event.request let body = await request.clone().text() let hash = await sha256(body) let cacheUrl = new URL(request.url) // get/store the URL in cache by prepending the body's hash cacheUrl.pathname = '/posts' + cacheUrl.pathname + hash // Convert to a GET to be able to cache let cacheKey = new Request(cacheUrl, { headers: request.headers, method: 'GET', }) let cache = caches.default //try to find the cache key in the cache let response = await cache.match(cacheKey) // otherwise, fetch response to POST request from origin if (!response) { response = await fetch(request) event.waitUntil(cache.put(cacheKey, response)) } return response } addEventListener('fetch', event => { try { let request = event.request if (request.method.toUpperCase() === 'POST') return event.respondWith(handlePostRequest(event)) return event.respondWith(handleRequest(event)) } catch (e) { return event.respondWith(new Response('Error thrown ' + e.message)) } }) async function sha256(message) { // encode as UTF-8 const msgBuffer = new TextEncoder().encode(message) // hash the message const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer) // convert ArrayBuffer to Array const hashArray = Array.from(new Uint8Array(hashBuffer)) // convert bytes to hex string const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('') return hashHex } const someOtherHostname = 'my.herokuapp.com'

Cache TTL and Custom Keys

Determine how/if Cloudflare’s Classic CDN and Browsers will cache a resource by setting TTLs, cache keys, and cache settings.

Copy into a Worker script:
async function handleRequest(request) { let url = new URL(request.url) // Only use the path for the cache key, removing query strings // and always storing HTTPS e.g. https://www.example.com/file-uri-here let someCustomKey = `https://${url.hostname}${url.pathname}` let response = await fetch(request, { cf: { // Tell Cloudflare's Global CDN to always cache this fetch regardless of content type // for a max of 5 seconds before revalidating the resource cacheTtl: 5, // sets TTL to 5 and cacheEverything setting //Enterprise only feature, see Cache API for other plans cacheKey: someCustomKey, }, }) // must use Response constructor to inherit all of response's fields response = new Response(response.body, response) //Set cache control headers to cache on browser for 25 minutes response.headers.set('Cache-Control', 'max-age=1500') return response } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) })

CORS Header Proxy

Add necessary CORS headers to a third party API response

Copy into a Worker script:
async function handleRequest(request) { const url = new URL(request.url) const apiurl = url.searchParams.get('apiurl') // Rewrite request to point to API url. This also makes the request mutable // so we can add the correct Origin header to make the API server think // that this request isn't cross-site. request = new Request(apiurl, request) request.headers.set('Origin', new URL(apiurl).origin) let response = await fetch(request) // Recreate the response so we can modify the headers response = new Response(response.body, response) // Set CORS headers response.headers.set('Access-Control-Allow-Origin', url.origin) // Append to/Add Vary header so browser will cache response correctly response.headers.append('Vary', 'Origin') return response } function handleOptions(request) { // Make sure the necesssary headers are present // for this to be a valid pre-flight request if ( request.headers.get('Origin') !== null && request.headers.get('Access-Control-Request-Method') !== null && request.headers.get('Access-Control-Request-Headers') !== null ) { // Handle CORS pre-flight request. // If you want to check the requested method + headers // you can do that here. return new Response(null, { headers: corsHeaders, }) } else { // Handle standard OPTIONS request. // If you want to allow other HTTP Methods, you can do that here. return new Response(null, { headers: { Allow: 'GET, HEAD, POST, OPTIONS', }, }) } } addEventListener('fetch', event => { const request = event.request const url = new URL(request.url) if (url.pathname.startsWith(proxyEndpoint)) { if (request.method === 'OPTIONS') { // Handle CORS preflight requests event.respondWith(handleOptions(request)) } else if ( request.method === 'GET' || request.method === 'HEAD' || request.method === 'POST' ) { // Handle requests to the API server event.respondWith(handleRequest(request)) } else { event.respondWith(async () => { return new Response(null, { status: 405, statusText: 'Method Not Allowed', }) }) } } else { // Serve demo page event.respondWith(rawHtmlResponse(demoPage)) } }) // We support the GET, POST, HEAD, and OPTIONS methods from any origin, // and accept the Content-Type header on requests. These headers must be // present on all responses to all CORS requests. In practice, this means // all responses to OPTIONS requests. const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, HEAD, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', } // The URL for the remote third party API you want to fetch from // but does not implement CORS const apiurl = 'https://workers-tooling.cf/demos/demoapi' // The endpoint you want the CORS reverse proxy to be on const proxyEndpoint = '/corsproxy/' // The rest of this snippet for the demo page async function rawHtmlResponse(html) { return new Response(html, { headers: { 'content-type': 'text/html;charset=UTF-8', }, }) } const demoPage = ` <!DOCTYPE html> <html> <body> <h1>API GET without CORS Proxy</h1> <a target='_blank' href='https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful'>Shows TypeError: Failed to fetch since CORS is misconfigured</a> <p id='noproxy-status'/> <code id='noproxy'>Waiting</code> <h1>API GET with CORS Proxy</h1> <p id='proxy-status'/> <code id='proxy'>Waiting</code> <h1>API POST with CORS Proxy + Preflight</h1> <p id='proxypreflight-status'/> <code id='proxypreflight'>Waiting</code> <script> let reqs = {}; reqs.noproxy = async () => { let response = await fetch('${apiurl}') return await response.json() } reqs.proxy = async () => { let response = await fetch(window.location.origin + '${proxyEndpoint}?apiurl=${apiurl}') return await response.json() } reqs.proxypreflight = async () => { const reqBody = { msg: "Hello world!" } let response = await fetch(window.location.origin + '${proxyEndpoint}?apiurl=${apiurl}', { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(reqBody), }) return await response.json() } (async () => { for (const [reqName, req] of Object.entries(reqs)) { try { let data = await req() document.getElementById(reqName).innerHTML = JSON.stringify(data) } catch (e) { document.getElementById(reqName).innerHTML = e } } })() </script> </body> </html>`

Fetch HTML

Sends a request to a remote server, reads HTML from the response, then serves that HTML.

Copy into a Worker script:
async function handleRequest(request) { const init = { headers: { 'content-type': 'text/html;charset=UTF-8', }, } const response = await fetch(url, init) const results = await gatherResponse(response) return new Response(results, init) } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) }) /** * gatherResponse awaits and returns a response body as a string. * Use await gatherResponse(..) in an async function to get the response body * @param {Response} response */ async function gatherResponse(response) { const { headers } = response const contentType = headers.get('content-type') if (contentType.includes('application/json')) { return await response.json() } else if (contentType.includes('application/text')) { return await response.text() } else if (contentType.includes('text/html')) { return await response.text() } else { return await response.text() } } /** * Example someHost at url is set up to respond with HTML * Replace url with the host you wish to send requests to * */ const someHost = 'https://workers-tooling.cf/demos' const url = someHost + '/static/html'

Fetch JSON

Sends a GET request and reads in JSON from the response.

Copy into a Worker script:
async function handleRequest(request) { const init = { headers: { 'content-type': type, }, } const responses = await Promise.all([fetch(url1, init), fetch(url2, init)]) const results = await Promise.all([gatherResponse(responses[0]), gatherResponse(responses[1])]) return new Response(results, init) } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) }) /** * gatherResponse awaits and returns a response body as a string. * Use await gatherResponse(..) in an async function to get the response body * @param {Response} response */ async function gatherResponse(response) { const { headers } = response const contentType = headers.get('content-type') if (contentType.includes('application/json')) { return await response.json() } else if (contentType.includes('application/text')) { return await response.text() } else if (contentType.includes('text/html')) { return await response.text() } else { return await response.text() } } /** * Example someHost is set up to return JSON responses * Replace url1 and url2 with the hosts you wish to * send requests to * @param {string} url the URL to send the request to */ const someHost = 'https://workers-tooling.cf/demos' const url1 = someHost + '/requests/json' const url2 = someHost + '/requests/json' const type = 'application/json;charset=UTF-8'

Form Data

Serve an HTML form, then read POSTs from that form data.

Copy into a Worker script:
async function handlePostRequest(request) { let reqBody = await readRequestBody(request) let retBody = `The request body sent in was ${reqBody}` return new Response(retBody) } async function handleRequest(request) { let retBody = `The request was a GET ` return new Response(retBody) } addEventListener('fetch', event => { const { request } = event const { url } = request if (url.includes('form')) { return event.respondWith(rawHtmlResponse(someForm)) } if (request.method === 'POST') { return event.respondWith(handlePostRequest(request)) } else if (request.method === 'GET') { return event.respondWith(handleRequest(request)) } }) /** * rawHtmlResponse delievers a response with HTML inputted directly * into the worker script * @param {string} html */ async function rawHtmlResponse(html) { const init = { headers: { 'content-type': 'text/html;charset=UTF-8', }, } return new Response(html, init) } /** * readRequestBody reads in the incoming request body * Use await readRequestBody(..) in an async function to get the string * @param {Request} request the incoming request to read from */ async function readRequestBody(request) { const { headers } = request const contentType = headers.get('content-type') if (contentType.includes('application/json')) { const body = await request.json() return JSON.stringify(body) } else if (contentType.includes('application/text')) { const body = await request.text() return body } else if (contentType.includes('text/html')) { const body = await request.text() return body } else if (contentType.includes('form')) { const formData = await request.formData() let body = {} for (let entry of formData.entries()) { body[entry[0]] = entry[1] } return JSON.stringify(body) } else { let myBlob = await request.blob() var objectURL = URL.createObjectURL(myBlob) return objectURL } } const someForm = ` <!DOCTYPE html> <html> <body> <h1>Hello World</h1> <p>This is all generated using a Worker</p> <form action="/demos/requests" method="post"> <div> <label for="say">What do you want to say?</label> <input name="say" id="say" value="Hi"> </div> <div> <label for="to">To who?</label> <input name="to" id="to" value="Mom"> </div> <div> <button>Send my greetings</button> </div> </form> </body> </html>

Modify Request Property

Recommended practice for forming a request based off the incoming request. First, takes in the incoming request then modifies specific properties like POST body, redirect, and the Cloudflare specific property cf and runs the fetch.

Copy into a Worker script:
async function handleRequest(request) { /** * Best practice is to only assign new properties on the request * object (i.e. RequestInit props) through either a method or the constructor */ let newRequestInit = { // Change method method: 'POST', // Change body body: JSON.stringify({ bar: 'foo' }), // Change the redirect mode. redirect: 'follow', //Change headers, note this method will erase existing headers headers: { 'Content-Type': 'application/json', }, // Change a Cloudflare feature on the outbound response cf: { apps: false }, } // Change URL let url = someUrl // Change just the host url = new URL(url) url.hostname = someHost // Best practice is to always use the original request to construct the new request // thereby cloning all the attributes, applying the URL also requires a constructor // since once a Request has been constructed, its URL is immutable. const newRequest = new Request(url, new Request(request, newRequestInit)) // Set headers using method newRequest.headers.set('X-Example', 'bar') newRequest.headers.set('Content-Type', 'application/json') try { return await fetch(newRequest) } catch (e) { return new Response(JSON.stringify({ error: e.message }), { status: 500 }) } } addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) /** * Example someHost is set up to return raw JSON * @param {string} someUrl the URL to send the request to, since we are setting hostname too only path is applied * @param {string} someHost the host the request will resolve too */ const someHost = 'example.com' const someUrl = 'https://foo.example.com/api.js'

Modify Response

Recommended practice for mutating a fetched response. First, fetches a request then modifies specific properties which are immutable: status, statusText, headers and body.

Copy into a Worker script:
async function handleRequest(request) { /** * Best practice is to only assign properties on the response * object (i.e. ResponseInit props) through either a method or the constructor * since properties are immutable */ let originalResponse = await fetch(request) let originalBody = await originalResponse.json() // Change status and statusText // Make sure to pass in originalResponse to preserving all parts // of the original response except the part we want to update. let response = new Response(originalResponse, { status: 500, statusText: 'some message' }) // Change response body by adding the foo prop let body = JSON.stringify({ foo: 'bar', ...originalBody }) response = new Response(body, response) // Add a header using set method response.headers.set('foo', 'bar') // Set destination header to the value of the source header if (response.headers.has(headerNameSrc)) { response.headers.set(headerNameDst, response.headers.get(headerNameSrc)) console.log( `Response header "${headerNameDst}" was set to "${response.headers.get(headerNameDst)}"`, ) } return response } addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) /** * @param {string} headerNameSrc the header to get the new value from * @param {string} headerNameDst the header to set based off of value in src */ const headerNameSrc = 'foo'//'Orig-Header' const headerNameDst = 'Last-Modified'

Post JSON

Sends a POST request with JSON data from the Workers script.

Copy into a Worker script:
async function handleRequest(request) { const init = { body: JSON.stringify(body), method: 'POST', headers: { 'content-type': 'application/json;charset=UTF-8', }, } const response = await fetch(url, init) const results = await gatherResponse(response) return new Response(results, init) } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) }) /** * gatherResponse awaits and returns a response body as a string. * Use await gatherResponse(..) in an async function to get the response body * @param {Response} response */ async function gatherResponse(response) { const { headers } = response const contentType = headers.get('content-type') if (contentType.includes('application/json')) { return await response.json() } else if (contentType.includes('application/text')) { return await response.text() } else if (contentType.includes('text/html')) { return await response.text() } else { return await response.text() } } /** * Example someHost is set up to take in a JSON request * Replace url with the host you wish to send requests to * @param {string} url the URL to send the request to * @param {BodyInit} body the JSON data to send in the request */ const someHost = 'https://workers-tooling.cf/demos' const url = someHost + '/requests/json' const body = { results: ['default data to send'], errors: null, msg: 'I sent this to the fetch', }

Redirect

Redirect a request by sending a 301 or 302 HTTP response

Copy into a Worker script:
async function handleRequest(request) { return Response.redirect(someURLToRedirectTo, code) } addEventListener('fetch', async event => { event.respondWith(handleRequest(event.request)) }) /** * Example Input * @param {Request} url where to redirect the response * @param {number?=301|302} type permanent or temporary redirect */ const someURLToRedirectTo = 'https://www.google.com' const code = 301

Send Raw HTML

Delivers an HTML page from HTML directly in the Worker script.

Copy into a Worker script:
async function handleRequest(request) { const init = { headers: { 'content-type': 'text/html;charset=UTF-8', }, } return new Response(someHTML, init) } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) }) const someHTML = `<!DOCTYPE html> <html> <body> <h1>Hello World</h1> <p>This is all generated using a Worker</p> <iframe width="560" height="315" src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen ></iframe> </body> </html> `

Send Raw JSON

Renders a response of type application/json to the client

Copy into a Worker script:
async function handleRequest(request) { const init = { headers: { 'content-type': 'application/json;charset=UTF-8', }, } return new Response(JSON.stringify(someJSON), init) } addEventListener('fetch', event => { return event.respondWith(handleRequest(event.request)) }) const someJSON = { result: ['some', 'results'], errors: null, msg: 'this is some random json', }

Featured Projects

More boilerplate projects. Requires installation of Wrangler.

The gallery is actively growing. The template creator allows you to share templates. Host a public repo, and then run wrangler generate https://github.com/<your-repo>. For archived recipes see the old docs.

Binast-Cf-Worker

Serve BinAST via a Cloudflare Worker

Paste this into your terminal:

Img-Color-Worker

Retrieve the dominant color of a PNG or JPEG image

Paste this into your terminal:
wrangler generate my-app https://github.com/xtuc/img-color-worker

Speedtest-Worker

Worker for measuring download / upload connection speed from the client side, using the Performance Timing API

Paste this into your terminal: