I'm writing a wrapper around fetch
that I would like to add something to the URL before making the request e.g. identifying query parameters. I can't figure out how to make a copy of a given a Request
object with a different URL than the original. My code looks like:
// My function which tries to modify the URL of the request
function addLangParameter(request) {
const newUrl = request.url + "?lang=" + lang;
return new Request(newUrl, /* not sure what to put here */);
}
// My fetch wrapper
function myFetch(input, init) {
// Normalize the input into a Request object
return Promise.resolve(new Request(input, init))
// Call my modifier function
.then(addLangParameter)
// Make the actual request
.then(request => fetch(request));
}
I tried putting the original request as the second arguent to the Request
constructor, like so:
function addLangParameter(request) {
const newUrl = request.url + "?lang=" + lang;
return new Request(newUrl, request);
}
which seems to copy most of the attributes of the old request but doesn't seem to preserve the body
of the old request. For example,
const request1 = new Request("/", { method: "POST", body: "test" });
const request2 = new Request("/new", request1);
request2.text().then(body => console.log(body));
I would expect to log "test", but instead it logs the empty string, because the body is not copied over.
Do I need to do something more explicit to copy all of the attributes correctly, or is there a nice shortcut that will do something reasonable for me?
I'm using the github/fetch polyfill, but have tested with both the polyfill and the native fetch
implementation in the lastest Chrome.
clone() The clone() method of the Request interface creates a copy of the current Request object. Like the underlying ReadableStream.
Cloning. Cloning in javascript is nothing but copying an object properties to another object so as to avoid creation of an object that already exists. There are a few ways to clone a javascript object. 1) Iterating through each property and copy them to a new object. 2) Using JSON method.
The request object is the main entry point for an application to issue a request to the Library - all operations on a URL must use a Request object. The request object is application independent in that both servers and clients use the same Request class.
It looks like your best bet is to read the body using the Body
interface that Requests implement:
https://fetch.spec.whatwg.org/#body
This can only be done asynchronously since the underlying "consume body" operation always reads asynchronously and returns a promise. Something like this should work:
const request = new Request('/old', { method: 'GET' });
const bodyP = request.headers.get('Content-Type') ? request.blob() : Promise.resolve(undefined);
const newRequestP =
bodyP.then((body) =>
new Request('/new', {
method: request.method,
headers: request.headers,
body: body,
referrer: request.referrer,
referrerPolicy: request.referrerPolicy,
mode: request.mode,
credentials: request.credentials,
cache: request.cache,
redirect: request.redirect,
integrity: request.integrity,
})
);
After doing that, newRequestP
will be a promise that resolves to the request you want. Luckily, fetch is asynchronous anyway so your wrapper shouldn't be significantly hampered by this.
(Note: Reading the body using .blob()
off of a request that does not have a body seems to return a zero-length Blob object, but it's incorrect to specify any body, even a zero-length one, on a GET or HEAD request. I believe that checking if the original request had Content-Type
set is an accurate proxy for whether it has a body, which is what we really need to determine.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With