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