Express.js Vue.js Tutorial By Example

Throughout this Vue.js with Node.js and Express tutorial we'll learn by example how to create a full-stack CRUD (Create, Read, Update and Delete) application.

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"> &#9998; </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.


comments powered by Disqus