Reducing Boilerplate around Axios Requests with JWT's

Laurynas asks the following:

Hello Stephen, thank you for the course, it helped greatly.

One think I can't seem to figure out is a neat way to reduce excess boilerplate in my project. Im using redux-thunk + axios just like you in your client code. Get JWT token, and I need to send it with each request to the server... Just like you do here: https://github.com/StephenGrider/AdvancedReduxCode/blob/master/auth/client/src/actions/index.js#L61

Since I have a ton of action creators where I have to add this, is there a good way to do this? I've looked at writing my own middleware, or just a helper function to wrap boilerplate code, but none of the solutions I came up with 'felt right'. I'd appreciate your tips.

Thank you.

Yep, I bet we can condense this down!

The best approach here is to write a wrapper around the Axios module itself, so that we can inject the JWT or API Key whenever a request is made. Here's a good starting point:

import _ from 'lodash';
import axios from 'axios';

const api = {
  get(url, options) {
    return axios.get(url, _.merge(options, {
      headers: { authorization: localStorage.getItem('token') }
    }));
  },
  post(url, data, options) {
    return axios.post(url, data, _.merge(options, {
      headers: { authorization: localStorage.getItem('token') }
    }));
  }  
};

export default api;

The _.merge stuff is in there to ensure that any additional options get passed in to the axios call. For example, if we wanted to add in some custom options to the 'axios.get' call, we would want to make sure that those options didn't get accidentally clobbered by the authorization header.

Note that this approach assumes the token will be available through localStorage. In the not-unlikely-case that we want to more dynamically specify the token, we could use ES2015 classes to put together a better interface.

import _ from 'lodash';
import axios from 'axios';

class Api {
  constructor(token) {
    this.token = token;
  }
  get(url, options) {
    return axios.get(url, _.merge(options, {
      headers: { authorization: this.token }
    }));
  }

  post(url, data, options) {
    return axios.post(url, data, _.merge(options, {
      headers: { authorization: this.token}
    }));
  }  
}

export default Api;

With this, we could create a new instance of the API client once we knew what the JWT is.

const api = new Api(myJwt);

Previous Post Next Post