65

https://github.com/MrFiniOrg/AxiosQuestion

I would like to have my project setup so that I do not have to specify the same request header in every http call.

I have searched this online but I have not been able to accomplish this in my project.

Would someone please assist me in resolving this issue I am having. I am new to react and axios and I am not sure how to configure this.

My project seems to be doing this but it is sending the request 2 times. One with the header and one without.

My axios call can be found in the app.js class component

UncleFifi
  • 825
  • 1
  • 6
  • 9

5 Answers5

134

You can specify config defaults that will be applied to every request.

Global axios defaults

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

For more specific info, please visit their docs.

UPDATE:

You can do it in two ways:

1. In your index.js file [meaning the top-level aka 'root' file] you can configure your request/ response methods. Something like this:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import axios from 'axios';

axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';
axios.defaults.headers.common['Authorization'] = 'AUTH TOKEN';
axios.defaults.headers.post['Content-Type'] = 'application/json';

axios.interceptors.request.use(request => {
    console.log(request);
    // Edit request config
    return request;
}, error => {
    console.log(error);
    return Promise.reject(error);
});

axios.interceptors.response.use(response => {
    console.log(response);
    // Edit response config
    return response;
}, error => {
    console.log(error);
    return Promise.reject(error);
});

ReactDOM.render( <App />, document.getElementById( 'root' ) );
registerServiceWorker();

2. Or you can create a new file, a new instance of your axios.js file to be precise, and import the configurations separately in your components where you might need them. You could name it, eg axiosConfig.js, and put your specific configs inside of it. Something like this:

axiosConfig.js

// First we need to import axios.js
import axios from 'axios';
// Next we make an 'instance' of it
const instance = axios.create({
// .. where we make our configurations
    baseURL: 'https://api.example.com'
});

// Where you would set stuff like your 'Authorization' header, etc ...
instance.defaults.headers.common['Authorization'] = 'AUTH TOKEN FROM INSTANCE';

// Also add/ configure interceptors && all the other cool stuff

instance.interceptors.request...

export default instance;

After that you would import this file to components that need it and use it instead of the previous Axios [node_modules] import, like this:

Example.js

import React, { Component } from 'react';
// import axios from 'axios'; We don't need this anymore
import axiosConfig from '../../axiosConfig'; // But instead our new configured version :)

class Example extends Component {
    state = {
        data: [],
        error: false
    }

    componentDidMount () {
        // We could name (import) it as axios instead, but this makes more sense here ... 
        axiosConfig.get('/posts' )
            .then(response => {
                   this.setState({data: response});
                });
            })
            .catch(error => {
                this.setState({error: true});
            });
    }

NOTE: You can combine these two methods as needed, but remember that the configurations made in your configAxios.js file will overwrite those made in your index.js file [if they are the same configurations, that is :) ]

Noam Yizraeli
  • 4,446
  • 18
  • 35
Dženis H.
  • 7,284
  • 3
  • 25
  • 44
  • 3
    At where, in `index.js`? – Pavindu May 18 '19 at 17:17
  • 1
    @Pavindu yes you can put it in `index.js`. Example: `axios.defaults.baseURL = process.env.REACT_APP_BE_URL;` – KenanBek Aug 04 '19 at 13:56
  • @mleister What you're doing is overwriting the defaults of the **`axios`** package to fit your needs for every *request*. So, wherever you need those special `axios` configurations you would *import* your newly created & modified file and used that, otherwise, you would import the axios npm module and use that, instead. – Dženis H. Sep 20 '20 at 20:16
  • 1
    Could you please show how to do the second way in a functional component? I have tried this way but I get 'Unhandled Rejection (TypeError): Cannot read property 'data' of undefined' (anonymous) function – Clancinio Nov 12 '20 at 04:34
  • Did you mean: `import axios from '../../axiosConfig';` ? – Srishti Gupta Apr 17 '21 at 12:25
  • @Srishti You're totally right. I've fixed the typo. Thanks. – Dženis H. Jun 28 '21 at 16:33
13

Using interceptors, it runs on each request so if the token changes (refreshes) then the next request picks up the new token. Check for existing values in the request to allow overriding of the header. Consider we are using any token generator and updating token in local storage. Here we are using keyclock object that is stored in localStorage

import * as axios from "axios";
axios.defaults.baseURL = process.env.REACT_APP_BASE_URL;

axios.interceptors.request.use(
  config => {
    if (!config.headers.Authorization) {
      const token = JSON.parse(localStorage.getItem("keyCloak")).token;

      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
    }

    return config;
  },
  error => Promise.reject(error)
);
Mayur Nandane
  • 309
  • 2
  • 8
8

I also had the same issue and solution was to locate them in index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import axios from 'axios';
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';
import App from './components/app/App';
import * as serviceWorker from './serviceWorker';

axios.defaults.baseURL = process.env.REACT_APP_BE_URL;

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root'),
);

serviceWorker.unregister();

Also, I use .env files to keep for example base urls:

.env.production

REACT_APP_BE_URL=http://production-url-to-backend/

.env.development

REACT_APP_BE_URL=http://localhost:3000/

And when you run locally .env.development will be used, for production build (npm run build) .env.production will be used.

KenanBek
  • 999
  • 1
  • 14
  • 21
2

You can put it in a file (as explained here) and then import it in the top level

import { CssBaseline } from "@mui/material";
import "./App.css";
import ProfilePage from "./view/Profile/ProfilePage";
import "./service/axios-config"; //<---import it here


function App() {
  return (
    <div className="App">
      <CssBaseline />
      <ProfilePage />
    </div>
  );
}

export default App;

instead of adding this code in the top level:

axios.defaults.baseURL = process.env.REACT_APP_BE_URL; 
MR J
  • 71
  • 5
0

I have a simple minimalistic method of setting axios config for request header and it handles global error.

import axios, { AxiosError, AxiosHeaders } from "axios";
import useAuthStore from "../hooks/useAuthStore";
import { BASE_URL } from "./config";
import { getItem } from "./storage";

   const axiosInstance = axios.create({
   baseURL: `${BASE_URL}`,
   headers: {
   "Access-Control-Allow-Origin": "*",
  },

});

axiosInstance.interceptors.request.use(
  async (config) => {
    const token = await getItem("jwtToken");
    if (config.headers)
        (config.headers as AxiosHeaders).set("Authorization", `Bearer 
     ${token}`);
      return config;
   },
   (error) => Promise.reject(error),
 );

 axiosInstance.interceptors.response.use(
   (response) => response,
    (error) => {
        if (error instanceof AxiosError && error.response?.status === 401) 
      {
        useAuthStore.setState({ signedInAs: undefined });
      }
      return Promise.reject(error);
     },
    );

   export default axiosInstance;

Note: The base URL is imported from another file while the useAuthStore is a custom hook from zustand that store the user state for authorization.