Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify the URL of a new Request Object in ES6

I'm just playing around the with Fetch API and I came across something that I can't seem to find the answer to. If I create a new request object like so:

let request = new Request('http://www.foo.com', {
  method: 'GET',
  mode: 'no-cors',
  headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
  })
});

If I then try and modify the URL (append a query string to it) I receive an error in the browser (Cannot assign to read only property). I know that usually with an object, you can set writable to 'True' but does this work the same for a request object?

The reason that I ask is that I am trying to append a querystring to the end of the URL. These options are in another object, which I've got the values of and concatenated into a string so that it's something like:

number=1&id=130&foo=bar etc.

Am I trying to over engineer what I am doing here?

like image 893
zik Avatar asked Mar 24 '17 16:03

zik


2 Answers

You can copy all the properties from the old request into a new one with a new url like so:

const init = { 
  method: 'GET',
  mode: 'no-cors',
  headers: new Headers({
    'Content-Type': 'application/x-www-form-urlencoded'
  })
};
const oldRequest = new Request("https://old-url.com", init);
const newRequest = new Request("https://new-url.com", oldRequest);

console.log(newRequest.mode === oldRequest.mode); // true
console.log(newRequest.headers.get('Content-Type') === oldRequest.headers.get('Content-Type')); // true
console.log(newRequest.method === oldRequest.method); // true
like image 174
Cypress Frankenfeld Avatar answered Nov 19 '22 07:11

Cypress Frankenfeld


Request object is immutable by design, don't try to change it.

I wish clone() instance method accepted options to be able to to tweak the cloned object, but it doesn't. So I came up with this function:

function appendQuery(urlOrReq, queryString) {
    // make sure we deal with a Request object even if we got a URL string
  const req = urlOrReq instanceof Request ? urlOrReq : new Request(urlOrReq);

  const {
    cache, credentials, headers, integrity, method,
    mode, redirect, referrer, referrerPolicy, url, body
  } = req;

  // Don't add query string if there's none
  const urlWithQuery = url + (!queryString ? '' : '?' + queryString);

  return new Request(urlWithQuery, {
    cache, credentials, headers, integrity, method,
    mode, redirect, referrer, referrerPolicy, body
  })
}

Here's the same in TypeScript (only the first line is different):

function appendQuery(urlOrReq: RequestInfo, queryString?: string): Request {
    // make sure we deal with a Request object even if we got a URL string
  const req = urlOrReq instanceof Request ? urlOrReq : new Request(urlOrReq);

  const {
    cache, credentials, headers, integrity, method,
    mode, redirect, referrer, referrerPolicy, url, body
  } = req;

  // Don't add query string if there's none
  const urlWithQuery = url + (!queryString ? '' : '?' + queryString);

  return new Request(urlWithQuery, {
    cache, credentials, headers, integrity, method,
    mode, redirect, referrer, referrerPolicy, body
  })
}

Here's how it works:

const req = new Request('https://google.com')
appendQuery(req, 'foo=42')
// => Request {method: "GET", url: "https://google.com?foo=42", headers: Headers, destination: "", referrer: "about:client", …}
like image 45
Mikhail Vasin Avatar answered Nov 19 '22 09:11

Mikhail Vasin