๐Click Here for Ionic Framework ReactJS and VueJS Tips/Tutorials?๐
In this post we are assuming you understand the basics of GraphQL, but are interested in how to use the Vue Composition API with GraphQL in VueJS
About GraphQL: This is one of the best places to start to get complete overview of GraphQL The Fullstack Tutorial for GraphQL.
Quickly Spinning Up A GraphQL Server
For this to be helpful, you need a graphql server to work with. In the past, that was always a challenge until I found this great package for quickly spinning up a local server, with data based on a json file/
npm install -g json-graphql-server
// db.js - in project root directory
module.exports = {
posts: [
{ id: 1, title: "Lorem Ipsum", views: 254, user_id: 123 },
{ id: 2, title: "Sic Dolor amet", views: 65, user_id: 456 },
],
users: [
{ id: 123, name: "John Doe" },
{ id: 456, name: "Jane Doe" }
],
comments: [
{ id: 987, post_id: 1, body: "Consectetur adipiscing elit", date: new Date('2017-07-03') },
{ id: 995, post_id: 1, body: "Nam molestie pellentesque dui", date: new Date('2017-08-17') }
]
}
Aarons-iMac:vue-gql-composition aaronksaunders$ json-graphql-server db.js
GraphQL server running with your data at http://localhost:3000/
You can now point your browser at the server and get the GraphiQL interface to check your data.
Getting The Setup For The VueJS App
After setting up your base project using vue-cli we need to add the required packages for apollo-composable
and graphql.
They are on separate lines for documentation purposes only...
npm install @vue/apollo-composable
npm install @vue/composition-api
npm install apollo-boost
npm install graphql
npm install vue-apollo
Next open main.js
to star to add the client information for the graphql support
Add the imports to for the API integration and creating the Apollo client
// GRAPHQL STUFF
import VueCompositionApi, { provide } from '@vue/composition-api'
import { DefaultApolloClient } from '@vue/apollo-composable'
import ApolloClient from 'apollo-boost'
Next lets create the apollo client, the url is from the output when we launched the json-graphql-server
.
// client apollo client
const apolloClient = new ApolloClient({
connectToDevTools: true,
uri: "http://localhost:3000"
})
And then finally we need to add the VueCompositionApi
plugin since we are still not running vue3
Now we us the provide function from the composition api to make the apollo functionality available to the other components in the application.
new Vue({
// add the client to vue object
setup () {
provide(DefaultApolloClient, apolloClient)
},
render: h => h(App),
}).$mount('#app')
Starting with Query - Get All Posts
We are not doing a deep dive into GraphQL so I will just briefly explain the query and the expected output.
This query will return the list of all of the posts and include the id of the associated user.
// QUERY
const ALL_POST_QUERY = gql`
{
allPosts {
id
title
user_id
}
}
`;
The query response object will look similar to this, so when accessing the data in the application it will be data.allPost[]
{
"data": {
"allPosts": [
{
"id": "1",
"title": "Lorem Ipsum",
"user_id": "123"
},
{
"id": "2",
"title": "Sic Dolor amet",
"user_id": "456"
},
{
"id": "10",
"title": "test",
"user_id": "10"
},
]
}
}
Now that we have the query set lets get to the component setup.
In the HelloWorld.vue
Component, we need to add our query and scaffold out the script section to support the new composition api.
First add the imports, and the query as a constant.
<script>
import { gql } from "apollo-boost";
import { useQuery } from "@vue/apollo-composable";
// QUERY
const ALL_POST_QUERY = gql`
{
allPosts {
id
title
}
}
`;
Next we will add the setup
section and include the useQuery
function, passing it in the query we want to run.
You can see that the useQuery
composible returns the following
-
result
- data response from the query -
loading
- true | false indicating the loading state of the query, can be used to provide a visual status of the query -
error
- error information if appropriate
export default {
name: "HelloWorld",
setup() {
// QUERY
const { result, loading, error } = useQuery(
ALL_POST_QUERY
);
return {
result,
loading,
error
};
},
methods: { }
};
</script>
If you run the application now and look in the vue-dev-tools, you will see the properties returned from the setup
function bound to the component as data properties.
Quickly put together some UI to show the query results. We are utilizing the loading
property returned from useQuery
to determined if we should display a loading messages and the using the result.allPosts
to render the objects when the query is completed and finally if there is an error
we show the error message.
<template>
<div>
<button @click="addPost">ADD POST</button>
<div v-if="loading">
<h2>Loading</h2>
</div>
<div v-else-if="error">
<h2>{{error}}</h2>
</div>
<div v-else>
<h2>Query Results</h2>
<div v-for="p in result.allPosts" :key="p.id">{{p}}</div>
</div>
</div>
</template>
Now A Mutation - Adding A Post
This mutation will add a post to the dataset. The way it is constructed require query parameters formatted as follows:
{ title: "New Post Title", id : 100, userId : 10 }
// MUTATION
const ADD_POST_MUTATION = gql`
mutation createPost($title: String!, $id: ID!, $userId: ID!) {
createPost(title: $title, views: 0, user_id: $userId, id: $id) {
id
title
}
}
`;
Next we will include in the existing setup
section the useMutation
function, passing it in the mutation we want to run.
We are structure this such that we will have access to a function createPost
exposed for us to call to execute the query that will be bound to the component.
Note that because we already are returning loading
& error
from useQuery
that we will need to structure the objects that we return a little differently.
// QUERY
const { result, loading, error } = useQuery(
ALL_POST_QUERY
);
// MUTATION <== NEW
const {
loading: mLoading,
error: mError,
mutate: createPost
} = useMutation(ADD_POST_MUTATION);
return {
result,
loading: loading || mLoading, <== NEW
error: error || mError, <== NEW
createPost <== NEW
};
//
In the template section of the component we will and an input field and a button for the user to enter the title
and the execute the createPost
method associated with the useMutation
composable.
<template>
<div>
<input type="text" v-model="title" placeholder="enter the title" />
<button @click="addPost">ADD POST</button>
...
</div>
</template>
Updating the Cache
After the item is added to the list, you will notice that it is not showing up in the list. The client will "update" items if they exist already but will not add new items to cache automatically... you need to do that.
there is an update
option on useQuery
that we can use to update the local apollo cache which will then update the UI.
when the update function is called the data we get is shaped as the response we defined in the mutation
data: {
createPost: {
id: "1586711727281"
title: "adssad"
views: 0
user_id: "200"
__typename: "Post"
}
}
we then use that data to update the apollo cache using the following code.
// MUTATION
const {
loading: mLoading,
error: mError,
mutate: createPost
} = useMutation(ADD_POST_MUTATION, {
update: (cache, { data: { createPost } }) => {
// get the posts from the cache...
const data = cache.readQuery({ query: ALL_POST_QUERY });
// add the new post to the cache
data.allPosts.push(createPost);
// write results back to cache
cache.writeQuery({ query: ALL_POST_QUERY, data });
}
});
Conclusion
That's it for this post, in the next part I will add update and delete, and then clean up the UI a bit to make it more presentable.
json-graphql-server: https://github.com/marmelab/json-graphql-server
@vue/apollo-composable: https://v4.apollo.vuejs.org/guide-composable
Top comments (6)
Hello Aaron, thanks a lot for sharing this useful tutor.
I would love to have some help with the following code shown below in picture. My Idea is to create a list of blogs using vue3 graphql composition api (django backend). Fetching and creating new blog works fine. However, I have some problem on creating router-link for the detail of the blog. I followed the the example provided on vue apollo page, it didn't help.
Homeview
Hi Aaron, thanks for sharing this elegant solution. I 've checked out your source code, but in IE it shows a blank page without errors due to the provide in the setup in main.js. Do you have a solution for this?
I will take a look on my windows machine
thanks a lot bro, very useful ๐๐๐
Hi Aaron, do you have any advice how to use apollo-composable with Apollo Local State Management? Particularly what's the best way to handle reactivity, or make local state "reactive"?
i am a visual person so if you have some code that would help me respond to your question.