Template Gallery

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.

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'

Rundown

One gotcha that Workers developers commonly encounter is with the ergonomics of the Request and Response constructors.

Unlike in the browser, it is common that a Workers developer needs to change one or more parts of an intercepted Request before passing it into a fetch call. It is common for developers to attempt to manually declare each part of the new Request/Response, an approach that is prone to error.

The best practice is to always use the original request to construct the new request, thereby cloning all the attributes except those you intend to change.

let newRequest = new Request(event.request, {..some changes..}) return fetch(newRequest)

Change RequestInit

Request’s object properties - RequestInit - should be set through a method (e.g. headers.set) or the constructor.

This acts as a merge, preserving all parts of the original request except the part we want to update.

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 }, } const newRequest = new Request(request, newRequestInit)

Change headers

Because the RequestInit object only merges at the top level, passing a headers object in this way will overwrite all existing headers, rather than merging them as you might want to do.

To that end, you can either…

Clone the headers, modify the new Headers object, then pass it in to RequestInit:

const headers = new Headers(event.request.headers) headers.add(‘X-Example’, ‘bar’) fetch(new Request(even.trequest, { headers } ))

Use the instance-level methods on the Headers class to make the modifications directly on the request:

const newRequest = new Request(event.request) // Set headers using method newRequest.headers.set(‘X-Example’, ‘bar’) newRequest.headers.set(‘Content-Type’, ‘application/json’)

Change URL

To change the URL we still want to follow the best practice of inheriting all props from original request, but now the URL should be the first argument. Applying the URL also requires a constructor since once a Request has been constructed, its URL is immutable.

let url = request.url // Change just the host url = new URL(url) url.hostname = someHost const newRequest = new Request(url, new Request(request, newRequestInit))

This works due to the fact that, while a Request object happens to contain all of the attributes of the options object that is passed to the constructor, the options object does not include the URL.