Using REST API with VueJS



  • I have an employees.json file stored in the “statics” folder of my local VueJS project. The Index.vue file is displaying data from that local employees.json file. However, the json file was downloaded from the website http://dummy.restapiexample.com/ which contains fake online REST APIs for testing and prototyping of sample applications which are using rest call to display listing and crud features.

    What I would like to do is use the REST library for Vue.js to load the /employee data found on http://dummy.restapiexample.com/ in real time, making update calls each time, instead of simply changing the json object stored in the employees.json file. In other words, instead of relying on the local json file for displaying the data, I would like to use the /employee data in the REST API instead. How is this done? Apparently I need Axios in order to make this possible. Do I need Vuex to complete this?

    <template>
      <div class="q-pa-md">
        <q-markup-table>
          <thead>
            <tr>
              <th class="text-left">Id</th>
              <th class="text-left">Employee Name</th>
              <th class="text-right">Employee Salary</th>
              <th class="text-right">Employee Age</th>
              <th class="text-right">Profile Image</th>
              <th class="text-right">Delete</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="(data, index) in myJson"
              :key="index"
            >
              <td class="text-left">{{data.id}}</td>
              <td class="text-right"><a
                  href="javascript:void(0)"
                  @click="editEmployee(data.id)"
                >{{data.employee_name}}</a></td>
              <td class="text-right">{{data.employee_salary}}</td>
              <td class="text-right">{{data.employee_age}}</td>
              <td class="text-right">{{data.profile_image}}</td>
              <td class="text-right">
                <q-btn
                  flat
                  icon="delete"
                  color="negative"
                  @click="deleteEmployee(data.id)"
                />
              </td>
            </tr>
          </tbody>
        </q-markup-table>
        <q-dialog
          v-model="editModal"
          @hide="cancelEditEmployee"
        >
          <q-card
            style="width: 700px; max-width: 80vw;"
            v-if="employee !== null"
          >
            <q-card-section>
              <div class="text-h6">Employee: {{employee.employee_name}}</div>
            </q-card-section>
    
            <q-card-section class="q-pt-none">
              <q-input
                outlined
                v-model="employee.employee_name"
                label="Employee Name"
                class="q-mb-md"
              />
    
              <q-input
                outlined
                v-model="employee.employee_salary"
                label="Salary"
                class="q-mb-md"
                type="number"
              />
    
              <q-input
                outlined
                v-model="employee.employee_age"
                label="Age"
                class="q-mb-md"
                type="number"
              />
            </q-card-section>
    
            <q-card-actions
              align="center"
              class="bg-white text-teal"
            >
              <q-btn
                label="Save"
                color="positive"
                @click="saveEmployee"
                v-close-popup
              />
              <q-btn
                color="negative"
                label="Cancel"
                v-close-popup
              />
            </q-card-actions>
          </q-card>
        </q-dialog>
      </div>
    </template>
    
    <script>
    import json from '../statics/employees.json'
    export default {
      data () {
        return {
          myJson: [],
          editModal: false,
          employee: null,
          editingIndex: null
        }
      },
      methods: {
        deleteEmployee (id) {
          this.$q.dialog({
            title: 'Confirm',
            message: 'Would you really like to delete?',
            cancel: true,
            persistent: true
          }).onOk(() => {
            var index = this.myJson.findIndex(e => e.id === id)
            if (index > -1) {
              this.myJson.splice(index, 1)
            }
          })
        },
        editEmployee (id) {
          var index = this.myJson.findIndex(e => e.id === id)
          if (index > -1) {
            this.editingIndex = index
            this.employee = JSON.parse(JSON.stringify(this.myJson[index]))
            this.editModal = true
          } else {
            console.log('something went wrong')
          }
        },
        cancelEditEmployee () {
          this.employee = null
          this.editingIndex = null
        },
        saveEmployee () {
          this.myJson[this.editingIndex] = JSON.parse(JSON.stringify(this.employee))
          this.editModal = false
        }
      },
      mounted () {
        this.myJson = JSON.parse(JSON.stringify(json)).data
      }
    }
    </script>
    


  • Yes. You need Axios to consume a web api. Whether or not state needs to be updated across your components determines your need for Vuex or not.

    Scott



  • update your mounted method to:

    mounted () {
        axios('http://dummy.restapiexample.com/data-path')
            .then(response => {
                this.myJson = JSON.parse(response.data)
            })
            .catch(error => console.log('Error',  error.message))
      }
    


  • I replaced the mounted () method at the bottom of my Javascript code with the example above, which now looks like this:

    <script>
    const axios = require('axios')
    import json from '../statics/employees.json'
    export default {
      data () {
        return {
          myJson: [],
          editModal: false,
          employee: null,
          editingIndex: null
        }
      },
      methods: {
        deleteEmployee (id) {
          this.$q.dialog({
            title: 'Confirm',
            message: 'Would you really like to delete?',
            cancel: true,
            persistent: true
          }).onOk(() => {
            var index = this.myJson.findIndex(e => e.id === id)
            if (index > -1) {
              this.myJson.splice(index, 1)
            }
          })
        },
        editEmployee (id) {
          var index = this.myJson.findIndex(e => e.id === id)
          if (index > -1) {
            this.editingIndex = index
            this.employee = JSON.parse(JSON.stringify(this.myJson[index]))
            this.editModal = true
          } else {
            console.log('something went wrong')
          }
        },
        cancelEditEmployee () {
          this.employee = null
          this.editingIndex = null
        },
        saveEmployee () {
          this.myJson[this.editingIndex] = JSON.parse(JSON.stringify(this.employee))
          this.editModal = false
        }
      },
      mounted () {
        axios('http://dummy.restapiexample.com/data-path')
          .then(response => {
            this.myJson = JSON.parse(response.data)
          })
          .catch(error => console.log('Error', error.message))
      }
    }
    </script>
    

    However, ESLint is reporting an error:

    In the import line at the top of the code, ESLint is saying “‘json’ is defined but never used”. I assume this is because I am importing the data from the REST API location and not from the local employees.json file anymore. Do I replace import/export with a different command?



  • Remove your import of json.

    Also, import axios. And, if you’re going to use it more often, you’ll probably want to “add” it.

    https://medium.com/quasar-framework/adding-axios-to-quasar-dbe094863728

    Scott



  • Okay, so very close to success. Following s.molinari’s advice, I created a new Quasar project, adding both ESLint and Axios during the installation, and copy/pasted the Index.vue code to the new project. I also edited the axios.js file as described in the link s.molinari sent. However, after doing all that, the dev screen just shows the top table header and not the table content in the REST API link.

    dev screen

    <template>
      <div class="q-pa-md">
        <q-markup-table>
          <thead>
            <tr>
              <th class="text-left">Id</th>
              <th class="text-left">Employee Name</th>
              <th class="text-right">Employee Salary</th>
              <th class="text-right">Employee Age</th>
              <th class="text-right">Profile Image</th>
              <th class="text-right">Delete</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="(data, index) in myJson"
              :key="index"
            >
              <td class="text-left">{{data.id}}</td>
              <td class="text-right"><a
                  href="javascript:void(0)"
                  @click="editEmployee(data.id)"
                >{{data.employee_name}}</a></td>
              <td class="text-right">{{data.employee_salary}}</td>
              <td class="text-right">{{data.employee_age}}</td>
              <td class="text-right">{{data.profile_image}}</td>
              <td class="text-right">
                <q-btn
                  flat
                  icon="delete"
                  color="negative"
                  @click="deleteEmployee(data.id)"
                />
              </td>
            </tr>
          </tbody>
        </q-markup-table>
        <q-dialog
          v-model="editModal"
          @hide="cancelEditEmployee"
        >
          <q-card
            style="width: 700px; max-width: 80vw;"
            v-if="employee !== null"
          >
            <q-card-section>
              <div class="text-h6">Employee: {{employee.employee_name}}</div>
            </q-card-section>
    
            <q-card-section class="q-pt-none">
              <q-input
                outlined
                v-model="employee.employee_name"
                label="Employee Name"
                class="q-mb-md"
              />
    
              <q-input
                outlined
                v-model="employee.employee_salary"
                label="Salary"
                class="q-mb-md"
                type="number"
              />
    
              <q-input
                outlined
                v-model="employee.employee_age"
                label="Age"
                class="q-mb-md"
                type="number"
              />
            </q-card-section>
    
            <q-card-actions
              align="center"
              class="bg-white text-teal"
            >
              <q-btn
                label="Save"
                color="positive"
                @click="saveEmployee"
                v-close-popup
              />
              <q-btn
                color="negative"
                label="Cancel"
                v-close-popup
              />
            </q-card-actions>
          </q-card>
        </q-dialog>
      </div>
    </template>
    
    <script>
    import axios from 'axios' // NOT const axios = require('axios')
    
    export default {
      data () {
        return {
          myJson: [],
          editModal: false,
          employee: null,
          editingIndex: null
        }
      },
      methods: {
        deleteEmployee (id) {
          this.$q.dialog({
            title: 'Confirm',
            message: 'Would you really like to delete?',
            cancel: true,
            persistent: true
          }).onOk(() => {
            var index = this.myJson.findIndex(e => e.id === id)
            if (index > -1) {
              this.myJson.splice(index, 1)
            }
          })
        },
        editEmployee (id) {
          var index = this.myJson.findIndex(e => e.id === id)
          if (index > -1) {
            this.editingIndex = index
            this.employee = JSON.parse(JSON.stringify(this.myJson[index]))
            this.editModal = true
          } else {
            console.log('something went wrong')
          }
        },
        cancelEditEmployee () {
          this.employee = null
          this.editingIndex = null
        },
        saveEmployee () {
          this.myJson[this.editingIndex] = JSON.parse(JSON.stringify(this.employee))
          this.editModal = false
        }
      },
      mounted () {
        axios
          .get('http://dummy.restapiexample.com/api/v1/employees')
          .then(response => {
            this.myJson = JSON.parse(response.data)
          })
          .catch(error => console.log('Error', error.message))
      }
    }
    </script>
    

    Axios.js is below:

    import axios from 'axios'
    const axiosInstance = axios.create({
      baseURL: 'https://api.example.com'
    })
    export default ({ Vue }) => {
      Vue.prototype.$axios = axios
    }
    export { axiosInstance }
    

    The same result occurs whether I have “import axios from ‘axios’” or “const axios = require(‘axios’)” in the first Javascript line. The table does not fill up with the API’s information.





  • Yes! That works. I had a slight feeling that JSON.parse command in the mounted () section didn’t look right but wasn’t sure how to replace it. Thanks a ton!



  • A follow-up:

    So using Axios, it’s possible to implement CRUD (Create, Read, Update and Delete) functionality in the database. In the previous example, the GET request was added at the end of the Javascript to get the list of employee information. Now if I wanted to add additional CRUD commands - like the DELETE request for a user to click the Delete button in any row and send a response back to the API saying to actually delete the row information, and refresh the grid - would I add them in the mounted () section of Javascript? The example below does not work:

     mounted () {
        this.$axios
          .get('https://dummy.restapiexample.com/api/v1/employees')
          .then(response => {
            this.myJson = response.data.data
          })
          .catch(error => console.log('Error', error.message))
      },
        this.$axios
          .delete('https://dummy.restapiexample.com/api/v1/employees')
          .then(response => {
            this.myJson = response.data.data
          })
          .catch(error => console.log('Error', error.message))
      }
    }
    


  • mounted is a Vue lifecycle hook. It only fires once, when the component is “mounted”.

    For the delete, you need a method that fires on the @click event of a button (or a confirmation dialog).

    This is very basic Vue/ JavaScript stuff. Don’t mean to be condescending, but you really should take to the books. We aren’t here to teach you Vue or JavaScript. Ok?

    For a good Vue course, I’d suggest taking this: https://www.udemy.com/course/vuejs-2-the-complete-guide

    Scott



  • Okay, I’ll do that. Thanks.


Log in to reply