Set default header for every fetch() request
Asked Answered
B

6

61

Is it possible, using the fetch API, to set default headers for every single request?
What I want to do is set an Authorization header whenever there is a json web token in the localStorage. My current solution is to set the headers with this function:

export default function setHeaders(headers) {
    if(localStorage.jwt) {
        return {
            ...headers,
            'Authorization': `Bearer ${localStorage.jwt}`
        }
    } else {
        return headers;
    }
}

Setting the headers in a fetch request would then look like this:

return fetch('/someurl', {
        method: 'post',
        body: JSON.stringify(data),
        headers: setHeaders({
            'Content-Type': 'application/json'
        })
    })

But there has to be a better way to do this. I'm currently developing a React/Redux/Express app if that is of any help.

Baste answered 29/6, 2017 at 8:57 Comment(1)
If for some reason you do not want to use existing wrappers around fetch, writing one to add authorization header should be straight forward.Hearty
E
39

Creating a fetch wrapper could solve your problem:

function updateOptions(options) {
  const update = { ...options };
  if (localStorage.jwt) {
    update.headers = {
      ...update.headers,
      Authorization: `Bearer ${localStorage.jwt}`,
    };
  }
  return update;
}

export default function fetcher(url, options) {
  return fetch(url, updateOptions(options));
}

You also get the added benefit of being able to switch your request client easily for all the calls in your application if you decide you like Axios or other package better. And you can do other things like check if options.body is an object and add the 'Content-Type: application/json header.

Eudy answered 22/5, 2019 at 13:26 Comment(0)
I
10

Andri Möll created a FetchDefaults.js mixin for fetch that sets fetch defaults:

var Url = require("url")
var assign = require("oolong").assign
var merge = require("oolong").merge
var PARSE_QUERY = false
var PROTOCOL_RELATIVE = true // Enable //example.com/models to mimic browsers.

exports = module.exports = function(fetch, rootUrl, defaults) {
  if (typeof rootUrl === "string") rootUrl = parseUrl(rootUrl)
  else defaults = rootUrl, rootUrl = null
  return assign(exports.fetch.bind(null, fetch, rootUrl, defaults), fetch)
}

exports.fetch = function(fetch, rootUrl, defaults, url, opts) {
  if (rootUrl != null) url = rootUrl.resolve(url)
  if (typeof defaults === "function") defaults = defaults(url, opts)
  return fetch(url, opts == null ? defaults : merge({}, defaults, opts))
}

function parseUrl(url) {
  return Url.parse(url, PARSE_QUERY, PROTOCOL_RELATIVE)
}

Distributed under AGPL-3.0-only license

Inactivate answered 29/6, 2017 at 9:40 Comment(0)
C
9

You could use Axios instead of fetch, with Interceptors

const setAuthorization = (token) => {

  api.interceptors.request.use((config) => {
    config.headers.Authorization = 'Bearer ' + token;
    return config;
  });

}

Where Api is an axios Object with a base URL

const api= axios.create({
  baseURL: 'http://exemple.com'
});

And when you get your token, u just have to call the function setAuthorization.

Source: Axios README.md

Cenis answered 29/6, 2017 at 9:21 Comment(1)
You can use axios to set your authorization headers and then use normal fetch request and the headers will be set for the fetch request as well.Poem
D
6

You can override default fetch api:

var originalFetch = window.fetch;
window.fetch = function (input, init) {
    if (!init) {
        init = {};
    }
    if (!init.headers) {
        init.headers = new Headers();
    }

    // init.headers could be: 
    //   `A Headers object, an object literal, 
    //    or an array of two-item arrays to set request’s headers.`
    if (init.headers instanceof Headers) {
        init.headers.append('MyHeader', 'Value');
    } else if (init.headers instanceof Array) {
        init.headers.push(['MyHeader', 'Value']);
    } else {
        // object ?
        init.headers['MyHeader'] = 'Value';
    }
    return originalFetch(input, init);
};

References:

Notes:

  • Despite I would not advise you to override the global fetch API, I already did this to include a header as a quickly and temporary fix to a production problem.
  • The best solution is to write your fetch like function that will always add your header and use it instead of original fetch. See other answers in this thread.
Deadly answered 14/6, 2022 at 17:44 Comment(0)
S
3

2024 answer

I would not advise you to override the global fetch API, you could run into issues if other libs or services depend on fetch.

Making a fetch wrapper is the way to go. In the following I'll assume that we want to preserve all fetch API behaviours.

First step: create a helper to merge the headers

Since the headers of the fetch API can be passed either as:

  • an object
  • an entries array (eg [['key1', 'val1'], ['key2', 'val2']])
  • an Headers instance

We will need a mergeHeaders helper. I'll pass on the details but this is a working implementation:

function mergeHeaders (...headerInits) {
   let result = {}
   headerInits.forEach((init) => {
      new Headers(init).forEach((value, key) => {
         if (value === 'null' || value === 'undefined') {
            // same as object spread: undefined overrides the current value
            // 'null' and 'undefined' got stringified in the process and are not valid headers values
            // therefore in this case we can remove the header
            delete res[key]
         } else {
            // add the header
            res[key] = value
         }
      })
   })
   return result
}

Second step: create the new fetcher

we can now proceed to implement a basic fetcher

function fetcher(input, options) {
    // your headers
    const defaultHeaders = { Authorization: localStorage.getItem('auth-header') }
    // merge them with the headers of the options
    const headers = mergeHeaders(defaultHeaders, options.headers)
    // add the headers to the options
    return fetch(input, { ...options, headers })
}

Third step: fix the autocomplete

If you don't use typescript you'll need to add a bit of jsdocs

jsdocs are type annotations that make use of the typescript lsp under the hood. They will enable autocomplete

/**
 * @type {typeof fetch}
 */
function fetcher(input, options) {
    // your headers
    const defaultHeaders = { Authorization: localStorage.getItem('auth-header') }
    // merge them with the headers of the options
    const headers = mergeHeaders(defaultHeaders, options.headers)
    // add the headers to the options
    return fetch(input, { ...options, headers })
}

Here we go, we have a fetcher with default headers!

If your use case starts becoming a bit more complex, consider using a library. I recently published my fetch API configuration library, called up-fetch

Here is a quick example using up-fetch

const fetcher = up(fetch, () => ({
    headers: { Authorization: localStorage.getItem('auth-header') }
}))

This achieves basically the same thing with a few differences: the response is automatically parsed, and an error is thrown if response.ok is false. There are many more features like params as objects, baseUrl config, validation adapters, interceptors...

Hope that helps

Subplot answered 22/4, 2024 at 21:51 Comment(0)
B
2

A quick and unrecommended hack is to redefine the default .fetch() function:

const oldFetch = window.fetch;
window.fetch = function() {
    arguments[1].headers = { 'blahblah' : 'blabla' };
    return oldFetch.apply(window, arguments);
}

Code is untested and unfinished. If you decide to use this answer, check arguments.length, add code to preserve existing headers, etc. etc. I'm just providing the direction for further exploration.

Brandy answered 24/4, 2022 at 14:19 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.