3
votes

I have a graphql api and a vue.js frontend with the apollo client for requesting data from the backend. It works fine so far.

The server answers with a new JWT-Token in every response header, which i need. So the solution should be simple .. a afterware which gets the new key from every response and updates the corresponding storage entry. But .. the headers are empty.

Here is the afterware:

apolloClient.networkInterface.useAfter([{
    applyAfterware({ response }, next) {
        if (process.env.NODE_ENV === 'development') {
            console.log('got new response', response);
        }
        if (response.status === 401) {
            store.commit('logout');
            store.commit('routeLogin');
        }
        next();
    }
}]);

Here is how the response looks:

screenshot from devtools console.log

And here is what in fact has been sent:

enter image description here

Do i miss something?

UPDATE

I've found a similar case in the issue tracker which has been solved by adding Access-Control-Expose-Headers. So i added them to mine server config. Now the response looks like this, while apollos headers object is still empty:

enter image description here

2

2 Answers

0
votes

You must remove {}.

from:

applyAfterware({res}, next) {

to:

applyAfterware(res, next) {

and now you get the full headerinformation.

apolloClient.networkInterface.useAfter([{
applyAfterware(res, next) {
        console.log("response:", res.options.headers);
        if (res.response.status === 401) {
            store.commit('logout');
            store.commit('routeLogin');
            // logout();
        }
        next();
    }
}]);
0
votes

For everyone looking for a way to get the response headers, here is my final solution:

import _ from 'lodash';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { ApolloLink, from } from 'apollo-link';
import { onError } from 'apollo-link-error';
import { InMemoryCache } from 'apollo-cache-inmemory';
// import { parse } from 'graphql'

import Auth from '@/store/api/system/auth';
import store from '@/store';

const ENDPOINT = `${process.env.VUE_APP_API_ENDPOINT}${process.env.VUE_APP_API_GRAPHQL_ROUTE}`;
const defaultHttpLink = new HttpLink({ uri: `${ENDPOINT}default` });
const adminHttpLink = new HttpLink({ uri: `${ENDPOINT}admin` });

const authMiddleware = new ApolloLink((operation, forward) => {
    // add the authorization to the headers

    let authorization = null;
    if (Auth.getToken('mimic')) {
        authorization = `Bearer ${Auth.getToken('mimic')}`;
    } else if (Auth.getToken()) {
        authorization = `Bearer ${Auth.getToken()}`;
    }

    operation.setContext({
        headers: { authorization }
    });

    return forward(operation).map(response => {
        const context = operation.getContext();
        const {
            response: { headers }
        } = context;

        if (headers) {
            const token = headers.get('Authorization');

            if (token) {
                const jwt = token.split('Bearer');
                if (jwt.length) {
                    const token = _.compact(jwt)[0].trim();
                    // console.log('fresh token: ', token);
                    // refresh correct token
                    let name = 'token';
                    if (Auth.getToken('mimic')) name = 'mimic';
                    store.commit('auth/addTokenToState', { token, name });
                }
            }
        }
        return response;
    });
});

const networkErrorLink = onError(({ response, networkError, operation, forward }) => {
    if (networkError) {
        switch (networkError.statusCode) {
            case 503: {
                const message = _.get(networkError, 'result.message');
                store.commit('updateMaintenanceState', message || true);
                response.errors = null;
                break;
            }
            case 404:
                // TODO
                // wenn ein menĂ¼ angefragt wird, das nicht da ist ...
                break;
            case 401:
            case 403:
            case 422:
                store.dispatch('auth/signout');
                break;
        }
    }

    return forward(operation);
});

export const defaultClient = new ApolloClient({
    link: from([networkErrorLink, defaultHttpLink]),
    cache: new InMemoryCache(),
    connectToDevTools: process.env.NODE_ENV === 'development'
});

export const adminClient = new ApolloClient({
    link: from([authMiddleware, networkErrorLink, adminHttpLink]),
    cache: new InMemoryCache(),
    connectToDevTools: process.env.NODE_ENV === 'development'
});

const apolloProvider = new VueApollo({
    clients: {
        default: defaultClient,
        admin: adminClient
    },
    defaultClient
});

Vue.use(VueApollo);

export default apolloProvider;

Be aware! You need to expose the headers (you want to get) on server side.