Valdo Romão Technical project manager

If you are willing to try GraphQL but you are not sure how to implement it in your VueJS application, this post is made for you. You will see that the configuration process as well as the implementation is quite simple thanks to a number of tools made just for us, lazy developers xD.

GraphQL is one of the most modern ways of building and querying APIs and (we think) is the futur standard for the APIs.

GraphQL gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools

-- graphql.org

In this post, we expect you to have a basic understanding of GraphQL. Also, a successful implementation of GraphQL requires a GraphQL server. This article only deals with the client side. For server implementations, you can have a look at Express-GraphQL (in NodeJS) or our very own GraphQLite in PHP.

Install it

In order to fully implement GraphQL in your Vue application you need to install graphql itself - of course :p - but also a bunch of tools which will considerably enhance your developer experience with GraphQL.

We use Apollo, a set of tools (client / server / engine / components...) built on top of GraphQL, to facilitate the querying of our graphql queries and mutations.

In order to integrate Apollo with VueJS, we use a third party package named vue-apollo. This is the default go-to package for Vue - Apollo integration.

Install GraphQL

yarn add graphql graphql-tag -D

Install Apollo third party package

yarn add vue-apollo -D

Install Apollo

yarn add apollo-client apollo-link apollo-link-error apollo-link-http -D

Configure it

Create a graphql directory in your root Vue project and place the index.js file which will set the graphql HTTP link as well as the Apollo client. We call this a "provider".

graphql/index.js

import Vue from 'vue';
import VueApollo from 'vue-apollo';
import ApolloClient from 'apollo-client';
import { HttpLink } from 'apollo-link-http';

Vue.use(VueApollo);

// All the graphql requests will be made at yourdomaine.com/graphql
const httpLink = new HttpLink({
    uri: '/graphql',
});

// We give this to the graphql client
const apolloClient = new ApolloClient({
    link: httpLink
});

// And we reference this client needed by vue-apollo
export default new VueApollo({
    defaultClient: apolloClient,
});

All the requests you are going to do will first transit into this file before reaching your components. It means you can intercept some code here in order to not have to do it in each components that are making requests with GraphQL. For example if you wanted to intercept requests made by non-authenticated users (401), you could do it in this file.

This is how the code would look like with those examples:

graphql/index.js

import Vue from 'vue';
import VueApollo from 'vue-apollo';
import ApolloClient from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { onError } from 'apollo-link-error';
// Notice the use of the link-error tool from Apollo

Vue.use(VueApollo);

const httpLink = new HttpLink({
    uri: '/graphql',
});

// we use a usefull error handling tool provided by Apollo in order to execute some code when errors occur.
const onErrorLink = onError(({ graphQLErrors, networkError }) => {
    // We log every GraphQL errors
    if (graphQLErrors) {
        graphQLErrors.map(({ message, locations, path }) =>
            console.log(
                `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
            ),
        );
    }
    // When a 401 error occur, we log-out the user.
    if (networkError) {
        if (networkError.statusCode === 401) {
            window.location.href = '/api/security/logout';
        }
    }
});

const apolloClient = new ApolloClient({
    link: onErrorLink.concat(httpLink)
});

export default new VueApollo({
    defaultClient: apolloClient,
});

When we write this line: window.location.href = '/api/security/logout'; We are expecting the server to respond on the URL /api/security/logout and actually to the job. We will not show how to do it because it's not the purpose of this post, but we have another post for that ;)

Then you need to pass the Apollo provider to the Vue instance in order to use it from the Vue components.

app.js

import apolloProvider from './graphql';
// Don't need to specify the name of the file if its name is index.js ;)

// ...

new Vue({
    template: '<App/>',
    components: { App },
    apolloProvider
}).$mount('#app');

Now we are going to use files with gql extension in order to make our requests. The first thing to do before going further is to add the loader for gql files in the Webpack configuration:

If you don't use Vue CLI you will have to add this configuration into your webpack.config.js

webpack.config.js

{
    test: /\.(graphql|gql)$/,
    exclude: /node_modules/,
    loader: 'graphql-tag/loader',
}

If you use Vue CLI, you can add this configuration into your vue.config.js:

vue.config.js

{
  test: /\.(graphql|gql)$/,
  use: [
    { loader: 'graphql-tag/loader' }
  ]
}

In the graphql directory you can then place your gql files, like so:

./graphql/roles/allRoles.gql is a query that will give us all the roles.

graphql/roles/allRoles.gql

query allRoles {
  allRoles {
    id,
    name
  }
}

./graphql/roles/role.gql is a query that will give us a specific role based on a role ID.

graphql/roles/role.gql

query role($roleID: String!) {
    role(roleID: $roleID) {
        id,
        nom,
        description,
        droits {
            id
        }
    }
}

"allRoles" and "role" are names of GraphQL Queries that you implemented server-side. If you also want to have a simple but powerful stack implementing GraphQL on the backend side, I highly recommend you to take a look at GraphQLite! At TheCodingMachine we now have multiple projects using GraphQLite for PHP and Apollo for Javascript and we are so happy with it that this is becoming a standard ;)

Use it

Once the configuration is done you can make a GraphQL query / mutation thank's to apollo, via a gql file.

Now we will do a 2 minutes pause, just to look at the options we have to finally get / set / display data.

With Apollo we have 3 different ways to achieve those goal through:

  1. The Apollo's components like <ApolloQuery>
  2. The apollo-client instance with this.$apollo
  3. The apollo vue option

Using the component

You can display the data directly into the html with the Apollo component <ApolloQuery> (if you just need to display):

Roles.vue

<ApolloQuery
        :query="require('../../graphql/roles/allRoles.gql')"
        :variables="{
            limit: limit,
            offset: offset
        }"
>
        <template slot-scope="{ result: { data, loading } }">
             <div v-if="loading">Loading...</div>
             <ul v-else>
                  <li v-for="role of data.allRoles">
                       {{ role.name }}
                  </li>
             </ul>
        </template>
</ApolloQuery>

Using the instance

You can also create a method that will do the job:

Role.vue

<template>
    <div>{{ role }}</div>
</template>

<script>
export default {
    data() {
        return {
            role: null
        }
    },
    created() {
        this.loadRole(roleID);
    },
    methods: {
        loadRole(roleID) {
            this.$apollo.query({
                    query: require("../../graphql/roles/role.gql"),
                    variables: {
                        roleID: roleID
                    }
                })
                .then(response => {
                    this.role = response.data.name;
                });
        }
    }
};
</script>

Using the object

Finally you could also write your code like this (for simple queries):

Roles.vue

<template>
    <ul v-if="roles">
        <li v-for="role of roles">
            {{ role.name }}
        </li>
    </ul>
</template>

<script>
// Do you remember the 'yarn add graphql-tag'? :p 
import gql from 'graphql-tag'

export default {
    apollo: {
        // Simple query that will update the 'roles' vue property
        roles: gql`query allRoles {
            allRoles {
                id,
                name
            }
        }`
    },
}
</script>

And voilà! Now you can enjoy all the power of GraphQL in your VueJS application ;)

About the author

Valdo is a project manager with a strong technical background. He loves playing with new technologies like GraphQL, VueJS, Symfony... and does his best to bring quality to his projects!