In this tutorial, I will show you how to build a Vue.js 2 CRUD Application to consume REST APIs, display and modify data using Vue 2, Vue Router and Axios.
More Practice:
– Vue.js JWT Authentication with Vuex and Vue Router
– Vue File Upload example using Axios
Fullstack:
– Vue.js + Node.js + Express + MySQL example
– Vue.js + Node.js + Express + PostgreSQL example
– Vue.js + Node.js + Express + MongoDB example
– Vue.js + Spring Boot + MySQL example
– Vue.js + Spring Boot + PostgreSQL example
– Vue.js + Spring Boot + MongoDB example
– Vue.js + Django example
Vuetify version: Vuetify data-table example with a CRUD App | v-data-table
Serverless with Firebase:
– Vue Firebase Realtime Database: CRUD example
– Vue Firestore: Build a CRUD App example
Newer version: Vue 3 CRUD example with Axios & Vue Router
Contents
- Overview of Vue.js 2 CRUD Application
- Vue.js App Component Diagram with Vue Router & Axios
- Technology
- Project Structure
- Setup Vue.js Project
- Add Vue Router to Vue.js 2 CRUD App
- Add Navbar and Router View to Vue.js 2 CRUD App
- Initialize Axios for Vue.js 2 CRUD HTTP Client
- Create Data Service
- Create Vue Components
- Configure Port for Vue.js 2 CRUD App
- Run Vue.js 2 CRUD App
- Conclusion
- Further Reading
- Source Code
Overview of Vue.js 2 CRUD Application
We will build a Vue.js front-end Tutorial Application in that:
- Each Tutorial has id, title, description, published status.
- We can create, retrieve, update, delete Tutorials.
- There is a Search bar for finding Tutorials by title.
Here are screenshots of our Vue.js 2 CRUD Application.
– Create a Tutorial:
– Retrieve all Tutorials:
– Click on Edit button to update a Tutorial:
On this Page, you can:
- change status to Published using Publish button
- delete the Tutorial using Delete button
- update the Tutorial details with Update button
– Search Tutorials by title:
The introduction above is for Vue.js Client with assumption that we have a Server exporting REST APIs:
Methods | Urls | Actions |
---|---|---|
POST | /api/tutorials | create new Tutorial |
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id |
PUT | /api/tutorials/:id | update a Tutorial by :id |
DELETE | /api/tutorials/:id | delete a Tutorial by :id |
DELETE | /api/tutorials | delete all Tutorials |
GET | /api/tutorials?title=[keyword] | find all Tutorials which title contains keyword |
You can find step by step to build a Server like this in one of these posts:
– Express, Sequelize & MySQL
– Express, Sequelize & PostgreSQL
– Express, Sequelize & SQL Server
– Express & MongoDb
– Spring Boot & MySQL
– Spring Boot & PostgreSQL
– Spring Boot & MongoDB
– Spring Boot & SQL Server
– Spring Boot & H2
– Spring Boot & Cassandra
– Spring Boot & Oracle
– Python/Django & MySQL
– Python/Django & PostgreSQL
– Python/Django & MongoDB
All of them can work well with this Vue App.
Vue.js App Component Diagram with Vue Router & Axios
– The App
component is a container with router-view
. It has navbar that links to routes paths.
– TutorialsList
component gets and displays Tutorials.
– Tutorial
component has form for editing Tutorial’s details based on :id
.
– AddTutorial
component has form for submission new Tutorial.
– These Components call TutorialDataService
methods which use axios
to make HTTP requests and receive responses.
Technology
- vue: 2.6.10
- vue-router: 3.1.3
- axios: 0.19.0
Project Structure
Let me explain it briefly.
– package.json contains 3 main modules: vue
, vue-router
, axios
.
– There are 3 components: TutorialsList
, Tutorial
, AddTutorial
.
– router.js defines routes for each component.
– http-common.js initializes axios with HTTP base Url and headers.
– TutorialDataService
has methods for sending HTTP requests to the Apis.
– vue.config.js configures port for this Vue Client.
You can also find a Typescript version for this Vue App in the tutorial:
Vue Typescript CRUD Application to consume Web API example
Setup Vue.js Project
Open cmd at the folder you want to save Project folder, run command:
vue create vue-js-client-crud
You will see some options, choose default (babel, eslint).
After the process is done. We create new folders and files like the following tree:
public
index.html
src
components
AddTutorial.vue
Tutorial.vue
TutorialsList.vue
services
TutorialDataService.js
App.vue
main.js
package.json
Open public/index.html, add bootstrap inside <head>
tag:
<!DOCTYPE html>
<html lang="en">
<head>
...
<title>vue-js-client-crud</title>
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
</head>
<body>
...
</body>
</html>
Add Vue Router to Vue.js 2 CRUD App
– Run the command: npm install vue-router
.
– In src folder, create router.js and define Router
as following code:
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
export default new Router({
mode: "history",
routes: [
{
path: "/",
alias: "/tutorials",
name: "tutorials",
component: () => import("./components/TutorialsList")
},
{
path: "/tutorials/:id",
name: "tutorial-details",
component: () => import("./components/Tutorial")
},
{
path: "/add",
name: "add",
component: () => import("./components/AddTutorial")
}
]
});
– Open src/main.js, then import router
:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
Let’s open src/App.vue, this App
component is the root container for our application, it will contain a navbar
.
<template>
<div id="app">
<nav class="navbar navbar-expand navbar-dark bg-dark">
<router-link to="/" class="navbar-brand">bezKoder</router-link>
<div class="navbar-nav mr-auto">
<li class="nav-item">
<router-link to="/tutorials" class="nav-link">Tutorials</router-link>
</li>
<li class="nav-item">
<router-link to="/add" class="nav-link">Add</router-link>
</li>
</div>
</nav>
<div class="container mt-3">
<router-view />
</div>
</div>
</template>
<script>
export default {
name: "app"
};
</script>
Initialize Axios for Vue.js 2 CRUD HTTP Client
Now we’re gonna install axios with command: npm install axios
.
Then, under src folder, we create http-common.js file like this:
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-type": "application/json"
}
});
Remember to change the baseURL
, it depends on REST APIs url that your Server configures.
For more details about ways to use Axios, please visit:
Axios request: Get/Post/Put/Delete example
Create Data Service
Our service will use axios from HTTP client above to send HTTP requests.
services/TutorialDataService.js
import http from "../http-common";
class TutorialDataService {
getAll() {
return http.get("/tutorials");
}
get(id) {
return http.get(`/tutorials/${id}`);
}
create(data) {
return http.post("/tutorials", data);
}
update(id, data) {
return http.put(`/tutorials/${id}`, data);
}
delete(id) {
return http.delete(`/tutorials/${id}`);
}
deleteAll() {
return http.delete(`/tutorials`);
}
findByTitle(title) {
return http.get(`/tutorials?title=${title}`);
}
}
export default new TutorialDataService();
Create Vue Components
As I’ve said before, we have 3 components corresponding to 3 routes defined in Vue Router.
Add item Component
This component has a Form to submit new Tutorial with 2 fields: title
& description
. It calls TutorialDataService.create()
method.
components/AddTutorial.vue
<template>
<div class="submit-form">
<div v-if="!submitted">
<div class="form-group">
<label for="title">Title</label>
<input
type="text"
class="form-control"
id="title"
required
v-model="tutorial.title"
name="title"
/>
</div>
<div class="form-group">
<label for="description">Description</label>
<input
class="form-control"
id="description"
required
v-model="tutorial.description"
name="description"
/>
</div>
<button @click="saveTutorial" class="btn btn-success">Submit</button>
</div>
<div v-else>
<h4>You submitted successfully!</h4>
<button class="btn btn-success" @click="newTutorial">Add</button>
</div>
</div>
</template>
<script>
import TutorialDataService from "../services/TutorialDataService";
export default {
name: "add-tutorial",
data() {
return {
tutorial: {
id: null,
title: "",
description: "",
published: false
},
submitted: false
};
},
methods: {
saveTutorial() {
var data = {
title: this.tutorial.title,
description: this.tutorial.description
};
TutorialDataService.create(data)
.then(response => {
this.tutorial.id = response.data.id;
console.log(response.data);
this.submitted = true;
})
.catch(e => {
console.log(e);
});
},
newTutorial() {
this.submitted = false;
this.tutorial = {};
}
}
};
</script>
<style>
.submit-form {
max-width: 300px;
margin: auto;
}
</style>
List of items Component
This component calls 3 TutorialDataService methods:
getAll()
deleteAll()
findByTitle()
components/TutorialsList.vue
<template>
<div class="list row">
<div class="col-md-8">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Search by title"
v-model="title"/>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button"
@click="searchTitle"
>
Search
</button>
</div>
</div>
</div>
<div class="col-md-6">
<h4>Tutorials List</h4>
<ul class="list-group">
<li class="list-group-item"
:class="{ active: index == currentIndex }"
v-for="(tutorial, index) in tutorials"
:key="index"
@click="setActiveTutorial(tutorial, index)"
>
{{ tutorial.title }}
</li>
</ul>
<button class="m-3 btn btn-sm btn-danger" @click="removeAllTutorials">
Remove All
</button>
</div>
<div class="col-md-6">
<div v-if="currentTutorial">
<h4>Tutorial</h4>
<div>
<label><strong>Title:</strong></label> {{ currentTutorial.title }}
</div>
<div>
<label><strong>Description:</strong></label> {{ currentTutorial.description }}
</div>
<div>
<label><strong>Status:</strong></label> {{ currentTutorial.published ? "Published" : "Pending" }}
</div>
<a class="badge badge-warning"
:href="'/tutorials/' + currentTutorial.id"
>
Edit
</a>
</div>
<div v-else>
<br />
<p>Please click on a Tutorial...</p>
</div>
</div>
</div>
</template>
<script>
import TutorialDataService from "../services/TutorialDataService";
export default {
name: "tutorials-list",
data() {
return {
tutorials: [],
currentTutorial: null,
currentIndex: -1,
title: ""
};
},
methods: {
retrieveTutorials() {
TutorialDataService.getAll()
.then(response => {
this.tutorials = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
refreshList() {
this.retrieveTutorials();
this.currentTutorial = null;
this.currentIndex = -1;
},
setActiveTutorial(tutorial, index) {
this.currentTutorial = tutorial;
this.currentIndex = index;
},
removeAllTutorials() {
TutorialDataService.deleteAll()
.then(response => {
console.log(response.data);
this.refreshList();
})
.catch(e => {
console.log(e);
});
},
searchTitle() {
TutorialDataService.findByTitle(this.title)
.then(response => {
this.tutorials = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
}
},
mounted() {
this.retrieveTutorials();
}
};
</script>
<style>
.list {
text-align: left;
max-width: 750px;
margin: auto;
}
</style>
If you click on Edit button of any Tutorial, the app will direct you to Tutorial page with url: /tutorials/:tutorialId
.
You can add Pagination to this Component, just follow instruction in the post:
Vue Pagination with Axios and API (Server Side pagination) example
Item details Component
For getting data & update, delete the Tutorial, this component will use 3 TutorialDataService methods:
get()
update()
delete()
components/Tutorial.vue
<template>
<div v-if="currentTutorial" class="edit-form">
<h4>Tutorial</h4>
<form>
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" id="title"
v-model="currentTutorial.title"
/>
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" class="form-control" id="description"
v-model="currentTutorial.description"
/>
</div>
<div class="form-group">
<label><strong>Status:</strong></label>
{{ currentTutorial.published ? "Published" : "Pending" }}
</div>
</form>
<button class="badge badge-primary mr-2"
v-if="currentTutorial.published"
@click="updatePublished(false)"
>
UnPublish
</button>
<button v-else class="badge badge-primary mr-2"
@click="updatePublished(true)"
>
Publish
</button>
<button class="badge badge-danger mr-2"
@click="deleteTutorial"
>
Delete
</button>
<button type="submit" class="badge badge-success"
@click="updateTutorial"
>
Update
</button>
<p>{{ message }}</p>
</div>
<div v-else>
<br />
<p>Please click on a Tutorial...</p>
</div>
</template>
<script>
import TutorialDataService from "../services/TutorialDataService";
export default {
name: "tutorial",
data() {
return {
currentTutorial: null,
message: ''
};
},
methods: {
getTutorial(id) {
TutorialDataService.get(id)
.then(response => {
this.currentTutorial = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
updatePublished(status) {
var data = {
id: this.currentTutorial.id,
title: this.currentTutorial.title,
description: this.currentTutorial.description,
published: status
};
TutorialDataService.update(this.currentTutorial.id, data)
.then(response => {
this.currentTutorial.published = status;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
updateTutorial() {
TutorialDataService.update(this.currentTutorial.id, this.currentTutorial)
.then(response => {
console.log(response.data);
this.message = 'The tutorial was updated successfully!';
})
.catch(e => {
console.log(e);
});
},
deleteTutorial() {
TutorialDataService.delete(this.currentTutorial.id)
.then(response => {
console.log(response.data);
this.$router.push({ name: "tutorials" });
})
.catch(e => {
console.log(e);
});
}
},
mounted() {
this.message = '';
this.getTutorial(this.$route.params.id);
}
};
</script>
<style>
.edit-form {
max-width: 300px;
margin: auto;
}
</style>
Configure Port for Vue.js 2 CRUD App
Because most of HTTP Server use CORS configuration that accepts resource sharing restricted to some sites or ports, so we also need to configure port for our App.
In project root folder, create vue.config.js file with following content:
module.exports = {
devServer: {
port: 8081
}
}
We’ve set our app running at port 8081
.
Run Vue.js 2 CRUD App
You can run our App with command: npm run serve
.
If the process is successful, open Browser with Url: http://localhost:8081/
and check it.
This Vue Client will work well with following back-end Rest APIs:
– Express, Sequelize & MySQL
– Express, Sequelize & PostgreSQL
– Express, Sequelize & SQL Server
– Express & MongoDb
– Spring Boot & MySQL
– Spring Boot & PostgreSQL
– Spring Boot & MongoDB
– Spring Boot & SQL Server
– Spring Boot & H2
– Spring Boot & Cassandra
– Spring Boot & Oracle
– Python/Django & MySQL
– Python/Django & PostgreSQL
– Python/Django & MongoDB
Conclusion
Today we’ve built a Vue.js 2 CRUD Application successfully with Vue Router & Axios. Now we can consume REST APIs, display and modify data in a clean way. I hope you apply it in your project at ease.
If you want a Typescript version for this Vue App, it is here:
Vue Typescript CRUD Application to consume Web API example
Or you can add Pagination Component:
Vue Pagination with Axios and API example
Or Vuetify version: Vuetify data-table example with a CRUD App | v-data-table
Happy learning, see you again!
Further Reading
For more details about ways to use Axios, please visit:
Axios request: Get/Post/Put/Delete example
Fullstack CRUD App:
- Vue.js + Node.js + Express + MySQL
- Vue.js + Node.js + Express + PostgreSQL
- Vue.js + Node.js + Express + MongoDB
- Vue.js + Spring Boot + MySQL
- Vue.js + Spring Boot + PostgreSQL example
- Vue.js + Spring Boot + MongoDB
- Vue.js + Django Rest Framework
Integration:
– Integrate Vue.js with Spring Boot
– Integrate Vue App with Node.js Express
Serverless with Firebase:
– Vue Firebase Realtime Database: CRUD example
– Vue Firestore: Build a CRUD App example
Source Code
You can find the complete source code for this tutorial on Github.
Newer version: Vue 3 CRUD example with Axios & Vue Router
This is a great tutorial. Well done sir. It’s of immense help to me
neat tutorial, but is it outdated ? when i change the .vue files, i keep getting error witch i think are related to depreciation, i have to keep wrapping code inside it with , and after that i get other errors
Hi, which Vue version do you use? If you need latest one, please visit:
Vue 3 CRUD example with Axios & Vue Router
Many thanks!
Try to search on google.com and I found your Vue tutorial. Very helpful and well-written. Thanks!
Great tutorial! I just completed it for some understanding with another project I’m working on and this has been very helpful!
Its possible I ran into errors due to messing up the initial file structure but here are some notes in case anyone else runs into these import errors as I did following ‘Vue.js + Node.js + Express + MongoDB example: MEVN stack CRUD Application’
I had to change the TutorialDataService imports under the components:
in tutorial:
import TutorialDataService from “../services/TutorialDataService”;
I changed to:
import TutorialDataService from “../../services/TutorialDataService”;
The http-common.js import under services/TutorialDataService.js I changed:
tutorial:
import http from “../http-common”;
changed to:
import http from “../src/http-common”;
Really enjoyed this tutorial!
I comment on this just to say thank you for the tutorial!
Excellent tutorial! Thanks!
Thank you for sharing!!!
on the place of ( id) if we use mongoDb we use (_id) so if anyone get a error write _id on the place of id .
Hello,
I have the following error at the very end of your tutorial and i don’t know why.
$ npm run serve
npm ERR! missing script: serve
Regards
Very good descriptions.
I wonder why in my case the promise response in array (tutorials in list page and searchByTitle) I need to use response.data.data instead of response.data.
I tried to print it out and returning observable object, containing ‘data’ attribute, so I use response.data.data and it works.
I had to run this in powershell to call vue create %project_name%
npm i -g @vue/cli @vue/cli-service-global
Would be helpful to add how to install/use Vue at the beginning of the tutorial for complete newbs.
Thanks! The tutorial is definitely what I need.
Thanks for sharing this nice tutorial.
Hi to anyone having cors errors, i changed my src/http-common.js to the following and it works now
import axios from “axios”;
export default axios.create({
baseURL: “http://localhost:8080/api”,
withCredentials: false,
headers: {
‘Access-Control-Allow-Origin’ : ‘*’,
‘Access-Control-Allow-Methods’:’GET,PUT,POST,DELETE,PATCH,OPTIONS’,
“Content-type”: “application/json”
}
});
Source: https://stackoverflow.com/questions/56297420/getting-network-error-when-calling-axios-get-request-in-react-js
from the reply made by “sheetal singh”
Hi, the backend works fine and there’s some data in MongoDB. The Vue frontend is running, but it has no data at all even though there is data shown in MongoDB. Also, I cant seem to be able to do any CRUD using the frontend. I tried adding a new tutorial and after submitting, nothing happened.
When I open the developer tools on chrome, it gave me this error and I have no idea how to fix it.
Error: Network Error
at createError (createError.js?2d83:16)
at XMLHttpRequest.handleError (xhr.js?b50d:81)
:8080/api/tutorials:1 Failed to load resource: net::ERR_CONNECTION_REFUSED
I really don’t know if I am putting these two tutorials together correctly. Your reply is appreciated.
Thanks for good tutorial but… CORS nightmare!
I’ve already blown a whole day on trying to fix it.. When will this nightmare end?? I just want to make a simple form and a pic uploader website for my kid. It’s embarrassing.
I followed the tutorial exactly. I even went back and copy/pasted it.
The proxy does not work, I beg you to please update this page when we figure it out.
See screenshot of Error, my code etc:
https://d.pr/i/Ulal8o
My github is here:
https://github.com/midlantica/vue-js-client-crud
Please help me!
Drew
Hi, it is not CORS problem.
500 Status code shows that your server is the break point, so you need to check the server.
Well ok, the first time I did it the way the tutorial shows and that didn’t work.
I get a ERR_CONNECTION_REFUSED error, screenshot:
https://d.pr/i/dErYh7
And here’s Firefox, screenshot:
“Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/api/tutorials. (Reason: CORS request did not succeed).”:
https://d.pr/i/VXCoJe
Here’s my ‘Tutorial-exact’ github repo:
https://github.com/midlantica/vue-js-client-crud/tree/Tutorial-exact
Again, thank you so much for your tutorials, this CORS thing seems to be a moving target. 🙂
You need middleware — https://expressjs.com/en/resources/middleware/cors.html
Or should change the .htaccess file if PHP servers like Apache, and use required response headers that you need in response in the server file. Othrwise the server will refuse – a security aspect
Having an issue connecting the vue front end to the mongo backen. The XMLHttprequest has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Any help is appreciated, thanks!
Hmm. I actually just installed this and it worked: https://github.com/expressjs/cors
and put this in the server.js
app.use(cors({origin: ‘http://localhost:8081’}));
I have this error when I try to get api response
Error: Request failed with status code 404
at createError (createError.js?2d83:16)
at settle (settle.js?467f:17)
at XMLHttpRequest.handleLoad (xhr.js?b50d:61)
bonjour super Tuto merci
how i use the demo in laravel , please give me instruction
Hi, i have problems with cors and i dont understand how you take necessary id. Help me please.
Thank you very much for this post.
I’m beginner with Vue and i need to learn fast.
Can you share some security integration using keycloak or other oauth2 service?.
Best Regards.
Hi, I will write the tutorials when having time 🙂
Thanks! I’m waiting for Vue 3 CRUD App from you.
Second this!
Muito Obrigado !
Thank You!
new to vue.js .
downlaoded from github and implemented . found this error while adding , submit not posting anything
https://snipboard.io/8I5NfF.jpg
Hi, you should use one of the backend servers that I provided in the tutorial.
Thx a lot for your tutorials. They are very helpful! 🙂
In my case, the app was running on port 8080, not 8081, even when using the vue.config.js file.
The reason was that you stated up here to create vue.config.js in the “src” folder.
In my case, I had to move it to the base folder “vue-js-client-crud” where the package.json resides.
Then it worked perfectly.
Ah yeah, we should put vue.config.js in the project root folder 🙂
Yes, you’re the MAN! I was trying to debugging the code, and it came out CORS errors…now I got data. Super!!
I’m so happy to know that you fixed it 🙂
hi, i am very new to veu and axios, i have created this tutorial and Spring Boot & MySQL/PostgreSQL. The backend is running OK (localhost:8083) with a few data in MySQL. This vue frontend is running without any errors (localhost:8082), but has no data at all. I think is Axios (baseURL is localhost:8083) is not working or set up correctly. And I really don’t know how to put these two tutorial together. Your reply is appreciated.
Hi, maybe the CORS configuration wasn’t modified for
localhost:8082
.Just looked at this this morning. I am working a lot using Django and tested this just against one of my REST Apis. Working nicelly. You can add Django REST Framework & Django & SQLite/PostgreSQL on your list. 🙂
I like the architectual idea of keeping services separated.
keep up!
Hi, I will write a tutorial for Django REST Framework & Django PostgreSQL soon.
At this time, you can read my tutorial for Django Rest Apis with MySQL database:
Django CRUD with MySQL example | Django Rest Framework
hello, i am new to veu and axios, i have created this tutorial and the Node.js Express & PostgreSQL: CRUD Rest APIs example with Sequelize but i had no clue that how to merge these two tutorial together. Your reply is appreciated.
Hi, you need to run both of them. Then open browser for Vue App, this client will connect to Node Express API automatically by our configuration in the tutorials.
thank u vry much , I have go through the project smoothly without any error
Its very good tutorial for vue beginner learners. Thank you very much, explained in a simple language.
Thank you so very much. I am a Vue beginner and this really helps me a lot.
Hi, I’m so happy to hear that 🙂
Your posts are really helpful to me.
Thank u.