Node Express.js, Vue.js & Mongoose|MongoDB Tutorial — CRUD By Example
Throughout this tutorial, you'll be using Node.js, Express.js and Vue.js to learn by example how to create a full-stack CRUD (Create, Read, Update and Delete) application. For database we'll be using MongoDB and Mongoose.
Express is a Node web framework that provides developers with essential elements to build web applications such as routing and templates etc.
Introduction
In this tutorial, we'll use Vue for the front-end and Node for the back-end of a full-stack web application.
The example application we'll be building will allow you to create, read, update and delete records from a MongoDB database with a Vue front-end interface. Express will be used for routing and REST API endpoints.
Start by creating a folder for your project by running the following command:
mkdir VueJSNodeProject
Navigate inside your newly created project and create a package.json
file:
cd VueJSNodeProject
touch package.json
Open the package.json
file and add the following content:
{
"name": "vuenodeproject",
"version": "1.0.0",
"description": "A Vue with Node and Express back end Project",
"scripts": {
},
"author": "",
"license": "MIT",
"devDependencies": {
}
}
Installing Back-End Dependencies
Now let's install the required dependencies:
npm install --save express body-parser cors mongoose nodemon
Creating The Express Server
Inside your project's root folder create a server.js
file and add the following content:
var express = require('express'),
path = require('path'),
bodyParser = require('body-parser'),
cors = require('cors'),
mongoose = require('mongoose');
mongoose.connect("mongodb://localhost:27017/vuenodedb").then(
() => {console.log('Database connection is successful') },
err => { console.log('Error when connecting to the database'+ err)}
);
const app = express();
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(cors());
var port = process.env.PORT || 4000;
app.listen( ()=>{
console.log('Listening on port ' + port);
});
You need to install MongoDB database system on your development machine.
Creating the Mongoose Model(s): Todo
Create a models folder inside your project and add a Todo.js
file with the following content:
const mongoose = require('mongoose');
const TodoSchema = mongoose.Schema({
name: String
}, {
timestamps: true
});
module.exports = mongoose.model('Todo', TodoSchema);
Our Todo
model is very simple as it only contains a name
field of type String
. We have also set timestamps to true which automatically adds two new fields: createdAt
and updatedAt
to the schema.
Creating Express Routes
First, let's require the Todo model:
var Todo = require('./models/Todo');
Next, let's instantiate an Express router:
var router = express.Router();
Creating a Todo: Express.js POST Route Example
Now let's add a POST route that handles HTTP POST requests. In the same file add the following code:
...
router.route('/create').post((req, res) => {
var todo = new Todo(req.body);
todo.save().then( todo => {
res.status(200).json({'message': 'Todo successfully added '});
})
.catch(err => {
res.status(400).send("Error when saving to database");
});
});
Getting Todos: Express.js GET Route Example
Next, let's add a GET route that handles HTTP GET requests. Add the following code:
router.route('/todos').get((req, res) => {
Todo.find((err, todos) =>{
if(err){
console.log(err);
}
else {
res.json(todos);
}
});
});
Getting a Todo by Id: Express.js GET by Id Route Example
router.route('/todos/:id').get((req, res) => {
var id = req.params.id;
Todo.findById(id, (err, todo) =>{
res.json(todo);
});
});
Updating a Todo by Id: Express.js PUT Route Example
router.route('/todos/:id').put((req, res) => {
Todo.findById(req.params.id, (err, todo) => {
if (!todo)
return next(new Error('Error getting the todo!'));
else {
todo.name = req.body.name;
todo.save().then( todo => {
res.json('Todo updated successfully');
})
.catch(err => {
res.status(400).send("Error when updating the todo");
});
}
});
});
Deleting a Todo by Id: Express.js DELETE Route Example
router.route('/todos/:id').get((req, res) => {
Todo.findByIdAndRemove({_id: req.params.id}, (err,todo) =>{
if(err) res.json(err);
else res.json('Todo successfully removed');
});
});
Starting your Express.js API Back-End
node server.js
You should have the following output in the terminal:
Listening on port 4000
Installing Vue CLI v3
We'll use the Vue CLI to generate the Vue front-end application. Let's start by installing the Vue CLI if you have not done so yet using the following command:
npm install --global @vue/cli
Generating a Vue Application Using Vue CLI v3
Let's now generate a new Vue application inside our project's root folder
$ vue create frontend
Next navigate inside your frontend
folder and install Axios by running the following command:
$ npm install --save axios
Axios is a Promise based HTTP client that we'll be using to make HTTP calls from our Vue front-end application to our Express.js REST API backend running at http://localhost:4000
with CORS enabled.
Creating Vue Components
Inside frontend/src/components
add two Vue components:
CreateTodo.vue
: for creating todos.ListTodo.vue
: for displaying fetched todos.
Creating a Todo
Open components/CreateTodo.vue
and add the following content:
<template>
<div id="container" class="container">
<div class="row">
<div class="col-sm-8 offset-sm-2">
<div class="alert alert-warning" v-show="showError" >
<button type="button" class="close" @click="hideMessage()">X</button>
<strong>Error!</strong>
</div>
<h1>Create a Todo</h1>
<div class="info-form">
<form>
<div class="form-group">
<label for="name">Todo name</label>
<input v-model="todo.name" type="text" class="form-control" id="name" aria-describedby="nameHelp" placeholder="Enter Name">
<small id="nameHelp" class="form-text text-muted">Enter your todo's name</small>
</div>
</form>
<button class="btn btn-primary" v-if="!this.todo.id" @click="createTodo()" ><span>Create</span>
<button class="btn btn-primary" v-if="this.todo.id" @click="updateTodo()" ><span>Update</span></button>
<button class="btn btn-primary" @click="newTodo()" >New..</button>
</div>
</div>
</div>
</div>
</template>
<script>
import {APIService} from '../APIService';
const apiService = new APIService();
export default {
name: 'CreateTodo',
components: {
},
data() {
return {
showError: false,
todo: {}
};
},
methods: {
createTodo(){
apiService.createTodo(this.todo).then((result)=>{
console.log(result);
if(result.status === 201){
this.todo = result.data;
}
},(error)=>{
this.showError = true;
});
},
updateTodo(){
apiService.updateTodo(this.todo).then((result)=>{
console.log(result);
},(error)=>{
this.showError = true;
});
},
newTodo(){
this.todo = {};
}
},
mounted() {
if(this.$route.params.pk){
apiService.getTodo(this.$route.params.pk).then((todo)=>{
this.todo = todo;
})
}
},
}
</script>
<style scoped>
.aform{
margin-left: auto;
width: 60%;
}
</style>
Listing Todos
Open components/ListTodo.vue
and add the following content:
<template>
<div>
<h1>Todos ()</h1>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="todo in todos" @click="selectTodo(todo)">
<th></th>
<td></td>
<td>
<button class="btn btn-danger" @click="deleteTodo(todo)"> X</button>
<a class="btn btn-primary" v-bind:href="'/todo-update/' + todo.id"> ✎ </a>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import {APIService} from '../APIService';
const API_URL = 'http://localhost:4000';
const apiService = new APIService();
export default {
name: 'ListTodo',
components: {
},
data() {
return {
todos: [],
numberOfTodos:0
};
},
methods: {
getTodos(){
apiService.getTodos().then((data) => {
this.todos = data.data;
this.numberOfProducts = data.count;
});
},
deleteTodo(todo){
apiService.deleteTodo(todo).then((r)=>{
if(r.status === 204)
{
alert("Todo deleted");
this.$router.go()
}
})
},
},
mounted() {
this.getTodos();
},
}
</script>
<style scoped>
.list-horizontal li {
display:inline-block;
}
.list-horizontal li:before {
content: '\00a0\2022\00a0\00a0';
color:#999;
color:rgba(0,0,0,0.5);
font-size:11px;
}
.list-horizontal li:first-child:before {
content: '';
}
</style>
Adding the API Service
import axios from 'axios';
const API_URL = 'http://localhost:8000';
export class APIService{
constructor(){
}
getTodos() {
const url = `${API_URL}/api/todos/`;
return axios.get(url).then(response => response.data);
}
getTodo(pk) {
const url = `${API_URL}/api/todos/${pk}`;
return axios.get(url).then(response => response.data);
}
deleteTodo(todo){
const url = `${API_URL}/api/todos/${todo.pk}`;
return axios.delete(url);
}
createTodo(todo){
const url = `${API_URL}/api/todos/`;
return axios.post(url,todo);
}
updateTodo(todo){
const url = `${API_URL}/api/todos/${todo.pk}`;
return axios.put(url,todo);
}
}
Conclusion
In this tutorial, we've created a CRUD application with Node.js and Vue which consumes a REST API created with Express.
-
Date: