DEV Community

Cover image for A Deep Dive into Strapi GraphQL
Shada for Strapi

Posted on • Originally published at strapi.io

A Deep Dive into Strapi GraphQL

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"
    }
Enter fullscreen mode Exit fullscreen mode

but instead he gets this:

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

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.

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
Enter fullscreen mode Exit fullscreen mode

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

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.

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.

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.

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

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

    yarn strapi install graphql
Enter fullscreen mode Exit fullscreen mode

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.

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.

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 fullscreen mode Exit fullscreen mode

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

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
      }
    }
Enter fullscreen mode Exit fullscreen mode

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
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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.

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
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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.

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
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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

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
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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

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.

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
      }
    }
Enter fullscreen mode Exit fullscreen mode

this would also return a jwt token for access like so

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 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
      }
    }
Enter fullscreen mode Exit fullscreen mode

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

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
      }
    }
Enter fullscreen mode Exit fullscreen mode

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

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 command:

    vue create strapiproject
Enter fullscreen mode Exit fullscreen mode

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 for details.

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

    npm run serve
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

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 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
Enter fullscreen mode Exit fullscreen mode

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">
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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')
Enter fullscreen mode Exit fullscreen mode

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 using NPM to continue.

    npm install vue-router
    OR
    yarn add vue-router
Enter fullscreen mode Exit fullscreen mode

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 },
      ],
    })
Enter fullscreen mode Exit fullscreen mode

Then add this router to your vue instance like so

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

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>
Enter fullscreen mode Exit fullscreen mode

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

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 URL 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},
      ],
    })
Enter fullscreen mode Exit fullscreen mode

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

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

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>
Enter fullscreen mode Exit fullscreen mode

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,
    };
Enter fullscreen mode Exit fullscreen mode

For more on GraphQL queries with Vue click here. 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>
Enter fullscreen mode Exit fullscreen mode

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;
          }
        },
      }, 
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

We used v-model="blog.Title" and v-model="blog.Body" to bind the post Title and Body to the respective form fields. @click="editPost()" 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");
            });
        },
Enter fullscreen mode Exit fullscreen mode

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

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

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},
      ],
    })
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

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

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},
      ],
    })
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

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");
    });
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (0)