Using Vue Apollo to Query Data
July 4, 2020
My first project where I had to use data from a GraphQL API was in my
quotes database
Opens in a new window . The quotes were all set up and I needed a tool to query them into my Vue.js project.
You can do so much more than query for data with Vue Apollo and I recommend you check it out. This post is only for querying since this is why I needed it and I found a few "gotchas" along the way that I wanted to clarify.
In this post I'll be using this
Pokemon API
Opens in a new window .
Table of Contents
Install
npm install --save vue-apollo graphql apollo-boost
Setup
The main.js
file needs to be configured to use Vue Apollo.
Import ApolloClient
from apollo-boost
and create a new instance containing the url for the API.
import ApolloClient from 'apollo-boost';
const apolloClient = new ApolloClient({
uri: 'https://graphqlpokemon.favware.tech/'
})
Then import the VueApollo
plugin from vue-apollo
and install it into Vue.
import VueApollo from 'vue-apollo';
Vue.use(VueApollo)
Finally, create a VueApollo
instance with its defaultClient
as the apolloClient
created before and add it to the app.
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
new Vue({
apolloProvider,
render: h => h(App),
}).$mount('#app')
Next step is optional. If using VS Code, you can install the
Apollo GraphQL
Opens in a new window extension. Then have a
apollo.config.js
file in the root of the project to configure it.
I kept everything the same as in the
docs
Opens in a new window , except changing the url to the API I'm using.
module.exports = {
client: {
service: {
name: 'my-app',
// URL to the GraphQL API
url: 'https://graphqlpokemon.favware.tech/',
},
// Files processed by the extension
includes: [
'src/**/*.vue',
'src/**/*.js',
],
},
}
Apollo Object
In a component, the queries need to be declared using the gql
from graphql-tag
.
import gql from 'graphql-tag';
There will be an apollo
object for mapping the query to local data.
A basic query will just have apollo
containing an attribute for the query, such as this simple query example from the
Vue Apollo docs
Opens in a new window with
hello
being the local data:
import gql from 'graphql-tag';
export default {
apollo: {
hello: gql`{hello}`,
}
}
Notice the backticks (``) used around the query.
You could also create a constant for the query and assign it like this:
import gql from 'graphql-tag';
const helloQuery = gql`{hello}`;
export default {
apollo: {
hello: {
query: helloQuery,
}
}
}
The data from this query can be accessed in the html like this:
<template>
<div class="apollo">
<h3>Hello</h3>
<p>
{{hello}}
</p>
</div>
</template>
The Pokemon API doesn't have any queries that don't require parameters, so the rest of the examples make use of what else Vue Apollo offers.
Examples:
Set Parameters
The gql
defines the query by encompassing the query in query{}
.
In this example, the values dragonite
for parameter pokemon
, true
for parameter reverse
and 1
for parameter take
are hard-coded.
import gql from 'graphql-tag';
export default {
name: 'App',
apollo: {
dragonite: {
query: gql`query{
getPokemonDetailsByName(pokemon: dragonite reverse: true take: 1) {
sprite
}
}`,
loadingKey: "Loading dragonite...",
update: data => data.getPokemonDetailsByName
}
}
}
I queried for the sprite
which is a gif that can be used in an img
tag:
<img :src="dragonite.sprite" />
The loadingKey
and update
will be explained in the Query Options section.
Reactive Parameters
The variables
option is useful when you don't want to hard-code the values. An example of this could be if you had the query running based on a user search input.
One addition to the previous example is that the types for each query parameter has to be defined. I created a name called getPokemon
to define this part. The name can be whatever you want - it doesn't affect the query. Only the parameter names and their types need to reflect the API's docs.
The query getDexEntries
receives the parameter pokemon
of type String!
(a string that is required, hence the exclamation point).
The variable defined pokemon
in the variables()
object is connected to $pokemon
in the getDexEntries
query.
import gql from 'graphql-tag';
export default {
name: 'App',
apollo: {
bulbasaur: {
query: gql`query getPokemon($pokemon: String!){
getDexEntries(pokemon: $pokemon) {
species
evos
}
}`,
loadingKey: "Loading bulbasaur...",
update: data => data.getDexEntries,
variables() {
return {
pokemon: "bulbasaur"
}
}
}
}
}
Reactive Query
You can set up conditionals to determine what query is called. Here I have an input for entering a pokemon name and another for entering the pokedex id. Depending if the name is entered, the getPokemonDetailsByFuzzy
query is called, else the getDexEntryByDexNumber
query is called if the id was given.
If neither input has a value, the query is skipped with the skip()
helper.
import gql from 'graphql-tag';
export default {
name: 'Search',
data() {
return {
name: "",
id: ""
}
},
apollo: {
searchedPokemon: {
query() {
//name
if(this.name !== "") {
return gql`query getWithName($pokemon: String!) {
getPokemonDetailsByFuzzy(pokemon: $pokemon) {
species
color
}
}`
}
// id
else if (this.id !== "") {
return gql`query getWithDexNumber($num: Float!){
getDexEntryByDexNumber(num: $num)
}`
}
},
loadingKey: "Loading...",
update: data => data.getPokemonDetailsByFuzzy || data.getDexEntryByDexNumber,
variables() {
return {
pokemon: this.name,
num: this.id
}
},
skip() {
return this.name === "" && this.id === ""
}
}
}
}
The update
helper doesn't know which query is being called so it needs to be set up to either map the first query or the second one. If you have more than 2 queries in a conditional, you would keep appending them with the ||
operator.
update: data => data.getPokemonDetailsByFuzzy || data.getDexEntryByDexNumber,
This is the html holding the search inputs and displaying the data once it's available.
<template>
<div class="hello">
<input v-model.trim="name" placeholder="name" />
<input v-model.trim.number="id" placeholder="id" />
<div v-if="searchedPokemon">
<ul>
<li>Species: {{searchedPokemon.species}}</li>
<li>Color: {{searchedPokemon.color}}</li>
</ul>
</div>
</div>
</template>
Query Options
Loading
The loadingKey
can be a message that shows while the data is loading. It's accessed by $apollo.queries.<query>.loadingKey
.
To know if the query is still loading, you can use $apollo.queries.<query>.loading
in a conditional. The paragraph containing the loading message "Loading dragonite..." will show until the sprite is ready to be displayed.
<p v-if="$apollo.queries.dragonite.loading">{{$apollo.queries.dragonite.loadingKey}}</p>
<img v-else :src="dragonite.sprite" />
Update
The update
option is important if the apollo query object is named differently from the query name itself. I normally change the names if they are too long or don't describe what data is being queried.
In the bulbasaur example, the data from getDexEntries
is mapped to the value bulbasaur
, the apollo object for this query.
update: data => data.getDexEntries
bulbasaur: {
query: gql`query getPokemon($pokemon: String!){
getDexEntries(pokemon: $pokemon) {
species
evos
}
}`,
loadingKey: "Loading bulbasaur...",
update: data => data.getDexEntries,
variables() {
return {
pokemon: "bulbasaur"
}
}
}
Skip
The query is skipped depending on the logic returned. There is an example of this being used in the Reactive Query section where the query is skipped if both inputs are clear.
skip() {
return this.name === "" && this.id === ""
}
Note
I noticed that despite the query working and the data being displayed, the editor may say there's an error in how the query is written.

It's odd, but I thought to mention it. 🤷♀
Conclusion
This post summarized everything I've come to understand so far when using the library. I hope this helps anyone else understand how to query with GraphQL in their Vue.js projects.
This example can be found in the
vue-apollo-example repo
Opens in a new window .
Resources: