A Deep Dive into Strapi GraphQL
Tags: graphql, restapi, cms, apollo
Published: 2021-08-12 12:10:46

## Introduction

REST API design pattern is one of the best practices when building API’s for the back end of any application. It’s benefits supersede it’s downside. When fetching data from an extensive REST application with many database relationships, there is can be an information overload problem. 

This post will explore 

- How GraphQL helps solve this problem and how implementing GraphQL in Strapi is even easier than we think.
- How to use of Apollo in Vue.js applications to make GraphQL queries to a Strap backend server
- Making CRUD requests using both the Strapi GraphQL playground and Apollo GraphQL in a Vue.js app
- Obtaining a JSON web tokens (JWT) for users in case of authenticated requests



## GraphQL Overview 


**Cons Of The REST API**

In a typical REST API-based application, data is fetched from the back end and displayed on the front end. There is the problem of overloading information (mentioned earlier). I'll further explain this using an example.

A front end developer wants to fetch just the `userName` of a user in the database. He expects his response to look like this

```
    user :{
      userName:"alloyking12300"
    }
```

but instead he gets this:

```
    user: {
      userName:"alloying12300",
      email:"testemail@email.com",
      age: 21,
      profile: {
        img:"image/path",
        profession:"developer"
      }
    }
```

Now you see, the response above is packed with lot of data that we do not need. It is, of course, possible to display what you need on the front end and be done with it, but this has a massive impact on the performance of the application. In the quest to solve this, GraphQL was born. 

Secondly, REST API applications have too many routes. In very complex applications, the routes can become challenging to handle and manage. GraphQL helps us tackle this too.

**GraphQL**

GraphQL is a query language for your API and a server-side runtime for executing queries using a type system you define for your data.

GraphQL provides developers access to just the particular data they need in a specific request by using just one endpoint (l like to think of it as a smart endpoint), which understands what the front end application expects and returns precisely.  

The bulk of the technicalities of implementing GraphQL have been simplified when using [Strapi](https://strapi.io/).


## Strapi GraphQL

Strapi is an easily customizable open-source headless CMS. Strapi’s API can return responses in both REST or GraphQL. In this tutorial, we will look at how GraphQL works in Strapi.

## Implementing GraphQL in Strapi

To explore the wonders of GraphQL in Strapi, we need a Strapi project to test. Let's proceed by creating a new Strapi project using the following command:

```
    yarn create strapi-app my-project --quickstart
    or
    npx create-strapi-app my-project --quickstart
```

This command will create a new Strapi project and launch it in your browser like this:


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1621600004384_register.PNG)


When you fill in this form, you will create your first Admin User. After that, the application will redirect to the dashboard.


## Blog Collection Type

We need content to test our GraphQL API. Let's create a blog collection type and add some blog posts to it.

On the left navigation menu, from the plugin section, click on Content-TypesBuilder. Fill the form to create a new Collection Type.

![](https://paper-attachments.dropbox.com/s_75763409C2F676A56666F5A72B9E5F7A23BC73D4BF13033A6B3418E998DD3AF1_1620384576736_ContentType.PNG)


We need to modify our Blog content type further to contain the **Title**, **Body**, and **Date** fields. These are necessary fields that we need. Fill the form and select these fields. You can use the images below for guidance.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1621603201815_BlogCollection.PNG)



![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625064825839_BlogContentType.png)


Repeat the process in the image above for the rest of the fields. Then save. After saving, we should have a newly created Collection Type of Blog. 


## Add Blog Posts

We have created our Collection Type. We need few blog posts to be able to explore how GraphQL works in Strapi.

From the Collection Type section in the navigation menu, click on **Blogs→Add new blog post**.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625065021333_createBlog.png)


Lets create a blog post with some dummy text as this is for educational purpose only
 

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625065117104_blogPost2.PNG)


 
To use GraphQL in Strapi, we need to install the GraphQL Plugin using the command below

```
    yarn strapi install graphql
```

On completion of the installation, our Strapi application is set for GraphQL. Strapi also has a Playground for testing GraphQL operations. We can access this Playground using `http://localhost:1337/graphql.`

The GraphQL Playground has an inbuilt text editor for you to enter your GraphQL commands, a play button for you to run your code and a screen to display the return values, error or success message.

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1621786761481_graphQLPlayGround.PNG)


Before we proceed to the Strapi playground to test, we need to grant the public user access to the Blogs collection type. Authentication will be covered later on in this post. For now, lets get started with the public user. To do this, click on **settings→roles→permissions** to grant all the necessary access to the Blogs and save.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625066172791_grantAccess.png)



## Strapi GraphQL Playground

The Strapi GraphQl playground is a development environment for you to interact with your Strapi application using GraphQl. Lets proceed by carrying out CRUD operations on our blog content using the playground.

In order to interact with the GraphQL server, we either need to write a **Query** or a **Mutation**.
A **GraphQL query** is used to read or fetch data from the server while a **mutation** is used to write or post values. For easier understanding you can think of it as GET request and POST request where Query is used to make GET request and Mutation to make POST request. 


## Fetching Multiple Contents

With that said, lets getting started by reading from our GraphQL server. We need to write a query for this. The code below is a basic GraphQL query to fetch all Blogs from our Strapi backend. It  returns the `Id`, `Title` and `Body`.

```
    query{
      blogs{
        id
        Title
        Body
      }
    }
```

Enter the code in your Strapi playground and it should fetch all Blog posts in your Blog collection 


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1622377664427_graphQLPlayGroundResult.PNG)



## Fetching Single Content:

We can fetch a single blog post from the collection by passing along a unique key. In our case, we will pass along the `id` . 

```
    query {
      blog(id:"3"){
        id
        Title
        Body
      }
    }
```

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625915489319_screen18.png)

## Create Content

Remember when we talked about Queries and Mutations earlier, we will use a Mutation to create a new entry. Lets create a new blog post to continue. 


```
    mutation {
      createBlog(input: { data: { Title: "Fifth Post", Body: " This is the fifth blog post. It  was created using a graphQl mutaiton from the strapi graphql playground" } }) {
        blog {
          Title
          Body
        }
      }
    }
```

The function `createBlog` accepts `input` object which in turn accepts a  `data` object with inputs to insert. This function derives its name from the name of the Strapi collection type. If we wanted to create a new user for instance, it would be `createUser` instead. The `Title` and `Body` are corresponding fields in the  `Blog` collection. In the case of a different collection type, they should correspond with the fields of the collection type.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625384229006_screen1.png)

## Update Content

We use Mutations for update features too. Lets edit the post we just created like so:

```
    mutation {
      updateBlog(
        input: {
          where: { id: "5" }
          data: { Title: "Fifth Post Edited", Body: "This is the fifth blog post (edited). This was created using a graphQl mutaiton from the strapi graphql playground" }
        }
      ) {
        blog {
          Title
          Body
        }
      }
    }
```

`updateBlog`  method accepts an `input` object that specifies the `id` of the post we intend to edit and the data in the `where` and `data` objects respectively. 


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625387252986_screen2.png)

## Delete Content

let us delete this post to see if it actually goes away. The Mutation below will do just that.

```
    mutation {
      deleteBlog(input: { where: { id: "5" } }) {
        blog {
          Title
          Body
        }
      }
    }
```    

`deleteBlog`  method accepts an `input` object with a `where` object that accepts the `id` of the post to delete. After a successful delete, the blog returns `null`

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625389040625_screen3.png)



## Authentication

In order for a user to access any protect route in Strapi, the user needs to be authenticated. We can implement authentication in our Strapi application using GraphQl too. Lets get started by creating a new user

```
    mutation {
      register(input: { username: "alloyuser", email: "email@gmail.com", password: "password" }) {
        jwt
        user {
          username
          email
        }
      }
    }
```

we used a new function here. The  `register` function which accepts an `intput` object that contains the user details to be created. 


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625405766235_screen4.png)


After successfully creating a user, it returns the `user`  object and a `jwt` token. We need the token to be passed along as  `Authorization` header in the form of `"Authorization": "Bearer YOUR_JWT_GOES_HERE"`. In the Strapi GraphQL playground, this can be set in the HTTP header section. That way it will be passed along with every request and user will be able to access protected routes.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625407387637_screen5.png)


In the case of an already existing user, Users can login to generate a token. Lets login using the details of the user we just created above.

```
    mutation {
      login(input: { identifier: "seconduser@gmail.com", password: "password" }) {
        jwt
      }
    }
```

this would also return a `jwt` token for access like so


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625407884205_screen6.png)



## Filters

To make more complex GraphQL queries, we can apply some filters to the query. Lets explore some of the most useful filters.


- `limit` type => integer : Places a limit on the number of returned data.
- `start`  type => integer: Ability to specify where the query will start.
- `sort` type => string: Sorts data to be returned
- `publicationState` type => PublicationState: Only select entries matching the publication state provided.
- `locale` type => string: This requires the [(i18n) plugin](https://strapi.io/documentation/developer-docs/latest/development/plugins/i18n.html) plugin to be activated and properly configured. It can be used to fetch contents from a selected locale
- Handled states are:
    - `live`: Return only published entries (default)
    - `preview`: Return both draft entries & published entries
- `<field>:asc` or `<field>:desc`
- `where` (object): Define the filters to apply in the query.
    - `<field>`: Equals.
    - `<field>_ne`: Not equals.
    - `<field>_lt`: Lower than.
    - `<field>_lte`: Lower than or equal to.
    - `<field>_gt`: Greater than.
    - `<field>_gte`: Greater than or equal to.
    - `<field>_contains`: Contains.
    - `<field>_containss`: Contains sensitive.
    - `<field>_ncontains`: Doesn't contain.
    - `<field>_ncontainss`: Doesn't contain, case sensitive
    - `<field>_in`: Matches any value in the array of values.
    - `<field>_nin`: Doesn't match any value in the array of values.
    - `<field>_null`: Equals null/Not equals null

To better understand how filters can be used, lets make a query to fetch all the Blog post with `id` greater than `2` 

```
    query {
      blogs(where: { id_gt: "2" }) {
        Title
        Body
      }
    }
```

Here we used the `where` object and `<field>_gt`.  `id` in our case is the `field` . We added the `gt` (greater than) prefix to get all post with `id` greater than `2`

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625474857799_screen7.png)


We can extend it further by adding a `limit` to the query and also sorting the result in descending order like so

```
    query {
      blogs(limit: 2, sort: "id:desc" where: { id_gt: "1" }) {
        Title
        Body
      }
    }
```

The result is a listed of sorted posts in descending order starting from the second post with an `id` of 2 downwards 


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625477957505_screen8.png)



## Explore Strapi GraphQL with Vue.js

Let's go a little further by interacting with Strapi GraphQL from an external Vue.js application. To get started, we need to create a Vue.js application. You can create it using the following [Vue CLI](https://cli.vuejs.org/) command:

```
    vue create strapiproject
```

Make sure you have the Vue CLI installed globally. If you need help installing the CLI or upgrading to the latest version of Vue.js, follow this tutorial [here](https://v3.vuejs.org/guide/installation.html#cli) for details.

After a successful installation, launch the project using the following command:

```
    npm run serve
```

Now you should be able to serve up the Vue.js application on the browser. Find a screenshot of my served screen below:


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1621889903452_vueGQ.PNG)



## Install Apollo

To interact with GraphQL from our Vue.js application, we need to install Apollo and query our Strapi GraphQL server using Apollo. 

Install Apollo using the following command:

```
    vue add apollo
```

Apollo boost and Apollo client are the two variations of Apollo that can be installed in a Vue.js application. We will proceed with the Apollo client as this best suits the purpose of this tutorial. Check Apollo official documentation for [more](https://apollo.vuejs.org/guide/installation.html#_1-apollo-client) details. 

Install Apollo client using the following command:

```
    npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
    Or:
    yarn add vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
```

In the HTML section, I used Bootstrap classes for basic styling. There are many different ways you can add bootstrap to your Vue.js project, but for this tutorial, I used a CDN (Content delivery network).  

Open **public→index.html**, add the following to the head section of the page:


       <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

add this before the closing **Body** tag of the page


    <!-- built files will be auto injected -->
        <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
    

After the installation, next, we need to configure Apollo to work in our application. Edit **src→main.js** file and add the following code

```
    import Vue from 'vue'
    import App from './App.vue'
    
    // import { createProvider } from './vue-apollo'
    Vue.config.productionTip = false
    
    // custom
    import VueApollo from 'vue-apollo'
    
    Vue.use(VueApollo)
    import { ApolloClient } from 'apollo-client'
    import { createHttpLink } from 'apollo-link-http'
    import { InMemoryCache } from 'apollo-cache-inmemory'
    
    // HTTP connection to the API
    const httpLink = createHttpLink({
      // You should use an absolute URL here
      uri: 'http://localhost:1337/graphql',
    })
    
    // Cache implementation
    const cache = new InMemoryCache()
    
    // Create the apollo client
    const apolloClient = new ApolloClient({
      link: httpLink,
      cache,
    })
    
    const apolloProvider = new VueApollo({
      defaultClient: apolloClient,
    })
    
    new Vue({
      // apolloProvider: createProvider(),
      apolloProvider,
      render: h => h(App)
    }).$mount('#app')
```
    

In the code above, `URI: 'http://localhost:1337/graphql``'`, points to the Strapi GraphQL endpoint. I have my Strapi server running in that port. Do not close your Strapi project while working on Vue.js.


## Vue Router

Now we have GraphQL configured and working in our app. Lets try fetching post from our GraphQL backend. This will require a router feature. Lets install [Vue router](https://router.vuejs.org/guide/#html) using NPM to continue. 

```
    npm install vue-router
    OR
    yarn add vue-router
```

Once its done installing, we need to configure the router to work with our application effectively. Head over to **src→main.js** and add the following block of code

```
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    
    
    const router = new VueRouter({
      mode: 'history',
      routes : [
        { path: '/', component: require('./components/HelloWorld.vue').default },
      ],
    })
```

Then add this `router` to your vue instance like so

```
     new Vue({
      apolloProvider,
      router: router,  //add this
      render: h => h(App)
    }).$mount('#app')
```

We created just one route for our home page. Lets edit our **App.vue** component to work with our router. Add the following 

```
    <template>
      <div id="app">
        <Nav />
        <router-view></router-view>
      </div>
    </template>
    <script>
    import Nav from "./components/Nav.vue";
    export default {
      name: "App",
      components: {
        Nav,
      },
    };
    </script>
 ```   
    

Notice the **Nav.vue** component. I added it for ease of navigation. The component was created in the **/components** directory. 


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625571797975_screen9.png)


Add the following to your **Nav** component to create a basic bootstrap navigation

```
    <template>
      <div>
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
          <router-link class="navbar-brand" to="/">Home</router-link>
          <button
            class="navbar-toggler"
            type="button"
            data-toggle="collapse"
            data-target="#navbarNav"
            aria-controls="navbarNav"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
              <li class="nav-item">
                <router-link class="nav-link" to="#">Link</router-link>
              </li>
              <li class="nav-item">
                <router-link class="nav-link" to="#">Link</router-link>
              </li>
            </ul>
          </div>
        </nav>
      </div>
    </template>
```

## Fetching Post

Lets make our actual GraphQL query from the Vue.js application to access data from the Strapi GraphQL server. 

Our Vue app has just one component at the moment named **HelloWorld**, I renamed mine to **Home**  Click on **src→components→Home.vue** and replace the content of the page with the following:

```
    <template>
      <div>
        <div class="container">
          <div class="container">
            <div class="customPadding">
              <div class="row">
                <div class="col-sm">
                  <div class="customCard">
                    <h1
                      style="
                        font-size: 3rem;
                        text-align: center;
                        padding-bottom: 6rem;
                      "
                    >
                      Blog Post
                    </h1>
                  </div>
                  <div v-for="blog in blogs" :key="blog.id">
                    <router-link
                      class="nav-link"
                      :to="{ path: '/blog/' + blog.id }"
                    >
                      <div class="container">
                        <div class="customCard">
                          <div
                            class="
                              card
                              shadow-lg
                              p-3
                              mb-5
                              bg-white
                              rounded
                              mr-5
                              ml-5
                            "
                          >
                            <div class="card-head" style="padding: 4rem">
                              <h1 style="font-size: 6rem">
                                {{ blog.Title }}
                                <hr />
                              </h1>
                            </div>
                            <div class="card-body text-center">
                              <p style="line-height: 26pt">{{ blog.Body }}</p>
                            </div>
                          </div>
                        </div>
                      </div>
                    </router-link>
                    <br />
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </template>
    <script>
    import gql from "graphql-tag";
    export default {
      name: "HelloWorld",
      data() {
        return {
          blogs: [],
        };
      },
      apollo: {
        blogs: {
          query: gql`
            query {
              blogs {
                id
                Title
                Body
              }
            }
          `,
        },
      },
    };
    </script>
    <style>
    .customPadding {
      margin-top: 12rem !important;
      margin-bottom: 12rem !important;
      /* padding: 4rem; */
    }
    </style>
  ```  

First, we imported `gql`, used in making our GraphQL query. We stored the response data from the query in `blogs:[]` array.

Next, the data in this array was looped through and displayed in the HTML section of this component. We added a router link to fetch each post to the displayed post in the loop. This router link accepts the post `id`. The `id` is passed along to the single post component. 

Lets register this newly created **UR**L as a route. To do this, open **main.js** once again and update the `router` with the newly created route like so

```
    const router = new VueRouter({
      mode: 'history',
      routes : [
        { path: '/', component: require('./components/Home.vue').default },
        { path: '/blog/:id', component: require('./components/SingleBlog.vue').default},
      ],
    })
```

We also need to create a new component named **SingleBlog.vue** The router link already points to it. Create this in the Components folder like so


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625587013827_screen11.png)



Now, your Vue app should be able to fetch data from the Strapi GraphQL server like my page below.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625586287779_screen10.png)



## Fetching Single Post

We already added a router link to each displayed blog post to fetch single post, add the following to our **SingleBlog.vue** component

```
    <template>
      <div>
        <div class="container customPadding">
          <div class="customPadding">
            <div class="card card shadow-lg p-3 mb-5 bg-white rounded mr-5 ml-5">
              <div class="container">
                <div class="card-head" style="padding: 4rem">
                  <h1 style="font-size: 6rem">{{ blog.Title }}</h1>
                </div>
                <hr />
                <p style="line-height: 26pt">
                  {{ blog.Body }}
                </p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </template>
    <script>
    import gql from "graphql-tag";
    export default {
      name: "SingleBlog",
      data() {
        return {
          blog: [],
          id: this.$route.params.id,
        };
      },
      apollo: {
        blog: {
          query: gql`
            query blog($id: ID!) {
              blog(id: $id) {
                id
                Title
                Body
              }
            }
          `,
          variables() {
            return {
              id: this.id,
            };
          },
        },
      },
    };
    </script>
    
    <style>
    .customPadding {
      margin-top: 12rem !important;
      margin-bottom: 12rem !important;
      /* padding: 4rem; */
    }
    </style>
```

Here, we modified our GraphQL query to fetch single post by passing the post `id` along with the query. If your observant, you will notice that the QraphQL query is a little different from the query in the playground. This is because in **Vue** we cannot access the value of `this.$route.params.id` from within the query. We have to pass it along as a variable using 

```
    variables() {
      return {
         id: this.id,
    };
```

For more on GraphQL queries with Vue click [here](https://apollo.vuejs.org/guide/apollo/queries.html#simple-query). If everything is done right, you should be able to click on a post from the home page and be redirected to a single page that will display the content of the post. 


## Delete Post

Lets take it even further by implementing the delete feature. Lets add a button for the delete functionality. Edit the code in **SingleBlog.vue** and the following in the `card-head` section of your `html`

```
    <div class="card-head" style="padding: 4rem">
                  <h1 style="font-size: 6rem">{{ blog.Title }}</h1>
                  <button type="button" class="btn btn-primary mr-2">Edit</button>
                  <button
                    type="button"
                    class="btn btn-danger"
                    @click="deletePost()"
                  >
                    Delete
                  </button>
                </div>
```


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625753416536_screen12.png)


Notice that we already add `@click="deletePost()`  to the **Delete Button**, that method is not yet created. In the JavaScript section of your component, add the following after the data function.

```
    methods: {
        deletePost() {
          const check = confirm();
          if (check) {
            this.$apollo
              .mutate({
                mutation: gql`
                  mutation deleteBlog($id: ID!) {
                    deleteBlog(input: { where: { id: $id } }) {
                      blog {
                        Title
                        Body
                      }
                    }
                  }
                `,
                variables: {
                  id: this.id,
                },
              })
          } else {
            return false;
          }
        },
      }, 
```

On click of the button, its call the `deletePost()`  function. We used a JavaScript confirm function to confirm before making the GraphQL query to delete the post. Notice that  `variables` in the GraphQl mutation is an object not a function like we have in the query earlier.  


## Edit Post

Lets take a look at how we can implement updating of our post content from within our Vue.js application. We need a form for this so I added a bootstrap Modal with a form to the **SingleBlog.vue** component using the following 

```
    <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">Edit Post</h5>
                <button
                  type="button"
                  class="close"
                  data-dismiss="modal"
                  aria-label="Close"
                >
                  <span aria-hidden="true">&times;</span>
                </button>
              </div>
              <div class="modal-body">
                <form>
                  <div class="form-group">
                    <label for="recipient-name" class="col-form-label"
                      >Title:</label
                    >
                    <input type="text" v-model="blog.Title" class="form-control" />
                  </div>
                  <div class="form-group">
                    <label for="message-text" class="col-form-label">Body:</label>
                    <textarea class="form-control" v-model="blog.Body"></textarea>
                  </div>
                </form>
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-primary" @click="editPost()">
                  Save
                </button>
              </div>
            </div>
          </div>
        </div>
```

The **Edit** button was also changed to contain code to open the modal like this


    <button type="button" class="btn btn-primary mr-2" data-toggle="modal" data-target="#exampleModal" data-whatever="@mdo"> Edit</button>

We used `v-model="blog.Title"` and `v-model="blog.Body"` to bind the post Title and Body to the respective form fields. `@click="editPo``s``t()``"` was called upon submission of the form. Lets add that function to the Methods object of our app like this.

```
    editPost() {
          this.$apollo
            .mutate({
              mutation: gql`
                mutation updateBlog($id: ID!, $Title: String!, $Body: String!) {
                  updateBlog(
                    input: {
                      where: { id: $id }
                      data: { Title: $Title, Body: $Body }
                    }
                  ) {
                    blog {
                      Title
                      Body
                    }
                  }
                }
              `,
              variables: {
                id: this.id,
                Title: this.blog.Title,
                Body: this.blog.Body,
              },
            })
            .then((res) => {
              console.log(res);
              alert("Edited");
            });
        },
```

The method looks a lot similar to that of the Delete function implemented above except for the data we passed along in this case and the additional two variable added `$Title: String!` and `$Body: String!` . But now you should be able to open and close the Edit form modal 


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625797473418_screen13.png)


 
 You should also be able to Edit post and save like so
 

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625798137659_screen14.png)

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625798176353_screen15.png)

##  Create A Post

 Thus far, we have covered Reading, Editing and Deleting post from our GraphQL server. Lets look at how we can create new post in this section. We need a new router and a new component for this feature. In your **Main.js** add a new route to the already existing 
 
```
     const router = new VueRouter({
      mode: 'history',
      routes : [
        { path: '/', component: require('./components/Home.vue').default },
    
        //add this
        { path: '/create', component: require('./components/CreatePost.vue').default },
        { path: '/blog/:id', component: require('./components/SingleBlog.vue').default},
      ],
    })
```
 
further more, we need to create the component that our newly created route points to. In **src→components** create a new component name **CreatePost.vue** like we have in the route.

Edit the content of the component and add the following code to it to display our form, validate and create a new post

```
    <template>
      <div class="container">
        <div class="mt-5">
          <div class="card-head" style="padding: 4rem">
            <h1 style="font-size: 6rem">
              Create New Post
              <hr />
            </h1>
          </div>
          <div class="card card shadow-lg p-3 mb-5 bg-white rounded mr-5 ml-5">
            <form>
              <div class="form-group">
                <label for="recipient-name" class="col-form-label">Title:</label>
                <input type="text" v-model="Title" class="form-control" />
              </div>
              <div class="form-group">
                <label for="message-text" class="col-form-label">Body:</label>
                <textarea class="form-control" rows="8" v-model="Body"></textarea>
              </div>
            </form>
            <div>
              <button type="button" class="btn btn-primary" @click="createPost()">
                Save
              </button>
            </div>
          </div>
        </div>
      </div>
    </template>
    <script>
    import gql from "graphql-tag";
    export default {
      data() {
        return {
          Title: "",
          Body: "",
        };
      },
      methods: {
        createPost() {
          if (this.Title && this.Body) {
            this.$apollo
              .mutate({
                mutation: gql`
                  mutation createBlog($Title: String!, $Body: String!) {
                    createBlog(input: { data: { Title: $Title, Body: $Body } }) {
                      blog {
                        Title
                        Body
                      }
                    }
                  }
                `,
                variables: {
                  Title: this.Title,
                  Body: this.Body,
                },
              })
              .then((res) => {
                console.log(res);
                alert("Post Created");
              });
          } else {
            alert("all fields are required");
          }
        },
      },
    };
    </script>
```

We used basic bootstrap to beautify our HTML form. Vue.js `v-model` was used to binned form values to its respective elements. in `createPost()` method, we validated this form and created our GraphQL query to create a new post. 
Lets edit the Navbar and add a link to this component.

```
    <template>
      <div>
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
          <router-link class="navbar-brand" to="/">Home</router-link>
          <button
            class="navbar-toggler"
            type="button"
            data-toggle="collapse"
            data-target="#navbarNav"
            aria-controls="navbarNav"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
              <li class="nav-item">
                <router-link class="nav-link" to="/create"
                  >Add New Post</router-link
                > //createPost Link added here
              </li>
              <li class="nav-item">
                <router-link class="nav-link" to="#">Link</router-link>
              </li>
            </ul>
          </div>
        </nav>
      </div>
    </template>
```

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625802048664_screen16.png)


lets go ahead and create a new post to see our form in action


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625916372504_screen19.png)


After creating the new post, you can find it in the home page like so

![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625916509335_screen20.png)


## Signup

We have been able to explore the CRUD feature of GraphQL using Vue.js. Let us scratch the surface of implementing authentication by creating a new user using GraphQL. A newly created user returns a `jwt` . When making request to protected routes in GraphQL, you need to pass the `jwt` token along with the request. 

With that said, lets proceed. We need to create a new route and a new component for this and also edit the navigation bar once more.

in **src→components** create a component name **Authentication.vue.** in the main.js, add a new route pointing to this component like so

```
    const router = new VueRouter({
      mode: 'history',
      routes : [
        { path: '/', component: require('./components/Home.vue').default },
        { path: '/create', component: require('./components/CreatePost.vue').default },
        { path: '/blog/:id', component: require('./components/SingleBlog.vue').default},
        //newly created route
        { path: '/user/signup', component: require('./components/Authentication.vue').default},
      ],
    })
```

edit the last link in the nav menu and add a link to the route

```
    <template>
      <div>
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
          <router-link class="navbar-brand" to="/">Home</router-link>
          <button
            class="navbar-toggler"
            type="button"
            data-toggle="collapse"
            data-target="#navbarNav"
            aria-controls="navbarNav"
            aria-expanded="false"
            aria-label="Toggle navigation"
          >
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
              <li class="nav-item">
                <router-link class="nav-link" to="/create"
                  >Add New Post</router-link
                >
              </li>
              <li class="nav-item">
                <router-link class="nav-link" to="/user/signup"
                  >sign up</router-link
                >
              </li>
            </ul>
          </div>
        </nav>
      </div>
    </template>
```

In the newly created component, add the following

```
    <template>
      <div class="container">
        <div class="mt-5">
          <div class="card-head" style="padding: 4rem">
            <h1 style="font-size: 6rem">
              Create New User
              <hr />
            </h1>
          </div>
          <div class="card card shadow-lg p-3 mb-5 bg-white rounded mr-5 ml-5">
            <form>
              <div class="form-group">
                <label for="recipient-name" class="col-form-label"
                  >User Name:</label
                >
                <input type="text" v-model="username" class="form-control" />
              </div>
              <div class="form-group">
                <label for="recipient-name" class="col-form-label">Email:</label>
                <input type="email" v-model="email" class="form-control" />
              </div>
              <div class="form-group">
                <label for="recipient-name" class="col-form-label">Password:</label>
                <input type="password" v-model="password" class="form-control" />
              </div>
              <div class="form-group">
                <label for="recipient-name" class="col-form-label">Password:</label>
                <input
                  type="password"
                  v-model="password_confirm"
                  class="form-control"
                />
              </div>
            </form>
            <div>
              <button type="button" class="btn btn-primary" @click="createUser()">
                Save
              </button>
            </div>
          </div>
        </div>
      </div>
    </template>
    <script>
    import gql from "graphql-tag";
    export default {
      data() {
        return {
          username: "",
          email: "",
          password: "",
          password_confirm: "",
        };
      },
      methods: {
        createUser() {
          if (
            this.username &&
            this.email &&
            this.password &&
            this.password_confirm
          ) {
            this.$apollo
              .mutate({
                mutation: gql`
                  mutation register(
                    $username: String!
                    $email: String!
                    $password: String!
                  ) {
                    register(
                      input: {
                        username: $username
                        email: $email
                        password: $password
                      }
                    ) {
                      jwt
                      user {
                        username
                        email
                      }
                    }
                  }
                `,
                variables: {
                  username: this.username,
                  email: this.email,
                  password: this.password,
                },
              })
              .then((res) => {
                console.log(res);
                alert("User created Created");
              });
          } else {
            alert("all fields are required");
          }
        },
      },
    };
    </script>
```

In our newly created component, we added a form, implemented slight authentication and made our GraphQL query to create a new user.


![](https://paper-attachments.dropbox.com/s_5BB4B57E7C13FFAD798C65F5C5ACBA9F2FE78507D0BD8DC2B28961C43F16EAC5_1625818780956_screen17.png)


After successfully creating the user, we will get back a response from our Strapi GraphQL containing the `jwt` token which will enable you carrying out every authenticated user feature. You can get access to the token from the response object.

```
    .then((res) => {
        console.log(res);
          alert("User created Created");
    });
```

## Conclusion:

Congratutlations, you've made it this far. By now, you should 


- Be able to setup GraphQL in Strapi
- Be able to run GraphQL queries and Mutations using the Strapi playground, and within a Vue.js application using Apollo.
- Be able to carry out CRUD request using GraphQL 
- Be able to Create an authentication system in Strapi using GraphQL

Now you have the basics. It's good enough to start building real-world projects. Remember to share your experience with the rest of the Strapi Community.

You can find the Vue.js project code base on GitHub [**here**](https://github.com/alloyking1/strapiGraphQL).