Web Development

Building a CRUD App with Vue and GraphQL

June 18th, 2019 | By Ahmed Bouchefra | 7 min read

In this tutorial, we’ll learn to build a CRUD app with Vue and GraphQL. We’ll use the Node backend we created in this previous tutorial.

You can find the source code of this demo for this GitHub repository.

Prerequisites

You will need several prerequisites for this tutorial:

  • Node.js and NPM are installed on your development machine. You can go to the official website to download both or use NVM to install Node.js in your system.

  • Knowledge of JavaScript and familiarity with Vue.

  • You have followed the previous tutorial for creating the GraphQL server.



If you have these prerequisites, let’s get started.

Enabling CORS in the Server

Since we are sending requests locally between two different ports, considered two separate domains, we’ll need to enable Cross-Origin Resource Sharing (CORS) in the server.

First, clone the code from the GitHub repository:

git clone https://github.com/JscramblerBlog/node-express-graphql-api.git


Next, navigate to your project and install the dependencies and the Cors module:

cd node-express-graphql-api
npm install
npm install cors --save


After that, open the index.js file and import the cors module:

    const cors = require('cors');


Then, add the Cors middleware to the Express app:

    const  app  =  express();
    app.use(cors())


Finally, start the server:

node index.js


Your GraphQL server will be available from the http://localhost:4000/ address.

Installing Vue CLI 3

We need to install Vue CLI to generate Vue projects and work with them. Open a new terminal and run the following command:

npm install -g @vue/cli


Meanwhile, @vue/cli v3.8.2 will be installed on your system.

Creating a Vue Project

Using Vue CLI, let’s proceed to create a Vue project. Head back to your terminal and run the following command:

vue create vue-graphql-demo  


When prompted to pick a preset, you can select the default one.

Wait for your project to be generated, and run the following commands to start the development server:

cd vue-graphql-demo
npm run serve


Your app will be running on the http://localhost:8080/ address.

Installing the Apollo Client

Apollo is a set of utilities to help you use GraphQL in your apps. It is well known for its client and its server.

Open a new terminal, navigate to your project’s folder, and run the following command to install the Apollo client in your Vue project:

npm install --save vue-apollo graphql apollo-boost


Apollo Boost is a zero-config way to start using Apollo Client. It includes some defaults, such as the recommended InMemoryCache and HttpLink, configured for you with the recommended settings. It is suitable for starting to develop fast.

In the src/main.js file, add the following code to create an instance of the Apollo client and connect it to our GraphQL server running at http://localhost:4000/graphql:

    import ApolloClient from "apollo-boost"
    import VueApollo from "vue-apollo"
    
    const apolloClient = new ApolloClient({
      uri: "http://localhost:4000/graphql"
    })
    
    Vue.use(VueApollo)
    const apolloProvider = new VueApollo({
      defaultClient: apolloClient,
    })


We import Apollo Client from the Apollo-boost package and VueApollo from the vue-apollo package. Next, we create an instance of the Apollo Client and pass in the URL of our GraphQL endpoint.

Then, we use the VueApollo plugin to integrate Apollo with our Vue application.

Finally, we create the Apollo Provider, which holds the instance of the Apollo Client that will be available to all Vue components.

All we have to do now is add the Apollo Provider to the Vue instance using the apolloProvider option:

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


We are now ready to use the Apollo client in our Vue app. See the docs for more information.

Consuming the GraphQL API

After adding vue-apollo to our app, all our components can use Apollo through the Apollo option.

First, open the src/App.Vue component and add the data() function to the exported object with the following variables:

    <script>
    export default {
      name: 'app',
      data(){
        return {
          id: null,
          firstName: '',
          lastName: '',
          email: ''}
      },

We define four component variables, which are id, firstName, lastName, and email. These will be bound to the HTML form for creating a new contact.

Sending a GraphQL Query for Reading Data

Next, import gql from the graphql-tag package and add the Apollo object to the component with the query that we’ll be making to read the contacts from the GraphQL API:

    <script>
    import gql from 'graphql-tag'
    
    export default {
      name: 'app',
      /* [...] */
      apollo: {
        contacts: gql`query {
          contacts {
            id,
            firstName,
            lastName,
            email
          }
        }`,
      },


gql is a JavaScript template literal tag that parses GraphQL query strings into the standard GraphQL AST. Find more information from the official repository.

In the Apollo object, we added a contacts attribute that will hold the results of the contacts query. Later, we’ll use it to display the contacts in the template.

Sending Mutation Queries for Creating, Updating, and Deleting Data

Next, add the createContact(), updateContact() and deleteContact() methods as follows:

      methods: {
        createContact(firstName, lastName, email){
          console.log(`Create contact: ${email}`)
          this.$apollo.mutate({
              mutation: gql`mutation createContact($firstName: String!, $lastName: String!, $email: String!){
                createContact(firstName: $firstName, lastName: $lastName, email: $email) {
                  id,
                  firstName,
                  lastName,
                  email}
              }`,
              variables:{
                firstName: firstName,
                lastName: lastName,
                email: email
              }
            }
          )
          location.reload();
        },
        updateContact(id, firstName, lastName, email){
          console.log(`Update contact: # ${id}`)
          this.$apollo.mutate({
              mutation: gql`mutation updateContact($id: ID!, $firstName: String!, $lastName: String!, $email: String!){
                updateContact(id: $id, firstName: $firstName, lastName: $lastName, email: $email)
              `,
              variables:{
                id: id,
                firstName: firstName,
                lastName: lastName,
                email: email
              }
            }
          )
          location.reload();
        },
        deleteContact(id){
          console.log(`Delete contact: # ${id}`)
          this.$apollo.mutate({
              mutation: gql`mutation deleteContact($id: ID!){
                deleteContact(id: $id)
              }`,
              variables:{
                id: id,
              }
            }
          )
          location.reload();
        },    
      }

In the three methods, we use this.$apollo.mutate() method to send mutations to the GraphQL server and we call the location.reload() method to reload the page.

See the docs for more information about sending mutations.

Next, add the selectContact() and clearForm() methods in the methods object:

        selectContact(contact){
          this.id = contact.id;
          this.firstName = contact.firstName;
          this.lastName = contact.lastName;
          this.email = contact.email;
        },
        clearForm(){
          this.id = null;
          this.firstName = '';
          this.lastName = '';
          this.email = '';
        }


These two methods will be used to select a contact from the table into the form and clear the form.

Adding the Template

Let’s now add a table and form for displaying, creating, updating, and deleting contacts. Let’s start with the HTML table:

    <template>
      <div id="app">
      <table border='1' width='100%' style='border-collapse: collapse;'>
       <tr>
         <th>First Name</th>
         <th>Last Name</th>
         <th>Email</th>
         <th>Actions</th>
       </tr>
    
       <tr v-for='contact in contacts'>
         <td>{{ contact.firstName }}</td>
         <td>{{ contact.lastName }}</td>
         <td>{{ contact.email }}</td>
         <td>
          <input type="button" @click="selectContact(contact)" value="Select">
          <input type="button" @click="deleteContact(contact.id)" value="Delete">
         </td> 
       </tr>
     </table>


We use the v-for directive to iterate over the contacts property of the Apollo object which holds the contacts fetched from the server. We also add two buttons for selecting and deleting the corresponding contact.

Next, let’s add the form below the table:

    </br>
        <form>
          <label>First Name</label>
          <input type="text" name="firstName" v-model="firstName">
          </br>
    
          <label>Last Name</label>
          <input type="text" name="lastName" v-model="lastName">
          </br>
    
          <label>Email</label>
          <input type="email" name="email" v-model="email">
          </br>
          
          <input v-if="!id" type="button" @click="createContact(firstName, lastName, email)" value="Add">
          <input v-if="id" type="button" @click="updateContact(id, firstName, lastName, email)" value="Update">
          <input type="button" @click="clearForm()" value="Clear">
          
        </form>
    
    </div>
    </template>


We created a form with three inputs that are bound to the firstName, lastName, and email variables declared in the component. We also added three buttons for creating a new contact, updating a selected contact, and clearing the form.

This is a screenshot of the UI after adding a bunch of data:

Data TableAfter selecting a contact using the Select button, it will be loaded in the form and the Update button will appear instead of the Add button:

Data Table with Update

Conclusion

In this tutorial, we’ve learned how to use the Apollo client to consume a GraphQL API. We’ve seen how to install Apollo, how to integrate it with Vue.js and send queries and mutations to read, create, update, and delete contacts from the database.

If you're building Vue applications with sensitive logic, be sure to protect them against code theft and reverse engineering.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Web Security

Build a GraphQL API with Node

Get started with GraphQL by building an API server with Node.js and Express which can be used to create, read, update and delete contacts from an SQLite DB.

May 24, 2019 | By Ahmed Bouchefra | 6 min read

Cybersecurity

Cryptography Introduction: Block Ciphers

Block ciphers are deterministic algorithms that allow securely protecting a single block of data. Here, we explain the different block cipher modes.

September 8, 2020 | By Jscrambler | 12 min read

Section Divider