Search code examples
apivue.jsvuexsettingsguard

How to initialize the Vue app depending on back-end response first?


I want some code to be ran before anything else in the app, that code will send a request to the Back-end and then update the store. I need that part to be executed first because route guards depend on it, how to achieve that?

Code Example

Fetching user information & settings

async init() {
    await AuthService.initCSRF();
    await AuthService.getUser().then((res) => {
      if (res.data && res.data.user) {
        this.loginLocally(res.data.user);
      } else {
        this.logoutLocally();
      }
    });
}

Auth guard

export function isLoggedIn(to, from, next) {
  console.log('Checked', store.state.auth.isLoggedIn);
  if (store.state.auth.isLoggedIn) {
    next();
    return;
  }

  next({ name: 'login' })
}

Solution

  • in my old project, I did something like this. hope you get some idea.

    app.js

    import App from './components/App.vue'
    store.dispatch('auth/attempt', sessionStorage.getItem('token')).then(() =>{
    new Vue({
        el: '#app',
        router,
        store,
        render: h => h(App),
     });
    });
    

    here I'm validating the token saved in local storage before rendering the app.

    my Vuex actions something like this

    async signIn({dispatch}, credentials) {
      let response = await axios.post("auth/signin", credentials);
      await dispatch('attempt', response.data.token)
    },
    
    
    async attempt({commit, state}, token) {
      if (token) {
        await commit('SET_TOKEN', token);
    
      }
      if (!state.token) {
        return;
      }
    
      try {
        let response = await axios.get('auth/me');
        commit('SET_USER', response.data)
      } catch (e) {
        commit('SET_TOKEN', null);
        commit('SET_USER', null);
      }
    },
    async signOut({commit}) {
      axios.post('auth/signout').then(() => {
        commit('SET_TOKEN', null);
        commit('SET_USER', null);
      });
    }
    

    I'm using a subscriber to listen to mutations and add or remove token in request headers

    import store from '../store'
    
    store.subscribe((mutation) => {
    
     if (mutation.type === 'auth/SET_TOKEN') {
      if (mutation.payload) {
       axios.defaults.headers.common['Authorization'] = `Bearer ${mutation.payload}`;
      sessionStorage.setItem('token', mutation.payload);
    } else {
      axios.defaults.headers.common['Authorization'] = null;
      sessionStorage.removeItem('token');
      }
     }
    });
    

    Finally an axios interceptor for handle token expiration.

    import router from '../plugins/router'
    import store from '../store'
    import axios from "axios";
    
    axios.interceptors.response.use((response) => {
    
      return response;
    }, (error) => {
    if (error.response.status) {
      if (error.response.status === 401) {
    
      if (router.currentRoute.name !== 'landing') {
        store.dispatch('auth/clearToken').then(() => {
          router.replace({
            name: 'landing'
          });
    
        }).finally(() => {
          swal.fire(
            'Your Session is Expired',
            'Please sign in again!',
            'error'
          )
        });
        }
      }
    }
    
    return Promise.reject(error);
    });