0

I am working on a ReactJS application, which uses many API calls to get data from the server. These API calls are organized into multiple classes and all of them use another class which issues a HTTP request using Axios.

Example markup and flow: (this is hand typed to keep it simple, please ignore any minor mistake or omissions)

class MyComponent extends Component{
   componentDidMount(){
      this.props.getData(//parameters//); //getData is an action bound via react-redux connect. 
   }
}

export const getData = (//parameters//) => (
  dispatch: any
) => {
  return new Promise((resolve, reject) => {
    //Some business logic
    let axiosService = new axiosService();
    axiosService .get(//parameters//).then((data: any) => {
      dispatch({
        type: "RECEIVE_DATA",
        payload: data
      });
      resolve();
    });
  });
};


export default class AxiosService {

  config: AxiosRequestConfig;
  url : string;

  constructor() {
    this.url = "http://localhost:8080/api/";

    this.config = {
      headers: {
//I want to inject Authorization token here
      },
      responseType: "json"
    };
  }



  get = () => {
    return new Promise((resolve, reject) => {
        resolve(axios.get(this.url, this.config));
      });
  };

}

Now I want to inject auth token as Authorization header when AxiosService makes an API call. This token is available in redux store. How can I access redux store in my service?

I can pass the token as a parameter to AxiosService get call, but that is messy. Based on my reading custom thunk middleware might help me here, but not sure how to update my service call. I have many actions, that need to use AxiosService.

user1868744
  • 963
  • 1
  • 13
  • 27
  • [Promise constructor antipattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). Also, use the redux HOC on the component that calls the service and pass auth as a parameter to the method call. – Jared Smith Aug 20 '19 at 22:28
  • @JaredSmith thanks for pointing the anti pattern. For the actual question, I am trying to avoid passing the token as parameter, instead add it just before making the API call so that adding new services will be less error prone. – user1868744 Aug 21 '19 at 04:22
  • Don't avoid it, wrap it instead: `const connect = (authtoken, url) => () => new AxiosService(authtoken, url)`. This has the advantage of making your class much easier to test. This isn't a law, but a good rule of thumb: pass parameters to functions and constructors rather than using global variables and hard-coded string and numeric constants. Never forget that a redux store is one big giant global variable! – Jared Smith Aug 21 '19 at 10:47

1 Answers1

0

There are many ways. For e.g. you can call Axios from the reducer or from the action builder. The reducer have the state, and redux-thunk is a popular library for that, that gives you the store to the Action Builder.

You can also use redux-saga, to listen to actions and perform http requests in response. redux-saga also gives you the store.

If you don't want all the libraries you can do a workaround. Where you created the store, save it to the global window:

window.store=redux.createStore(...)

Then, your http library can access the store:

window.store.getState()

It's not recommended way, but it's working.

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
  • Global variables are *evil*... and unnecessary in this case. OP needs to rework the service to take credentials as parameters. More testable, more maintainable. A component that calls the service can be connected to the store to pass them. – Jared Smith Aug 20 '19 at 22:31