Getting Started with the MERN Stack

Getting Started with the MERN Stack

The MERN stack consists of MongoDB, Express, React / Redux, and Node.js. Given the popularity of React on the frontend and of Node.js on the backend, the MERN stack is one of the most popular stack of technologies for building a modern single-page application.

The MERN stack consists of MongoDB, Express, React / Redux, and Node.js. Given the popularity of React on the frontend and of Node.js on the backend, the MERN stack is one of the most popular stack of technologies for building a modern single-page application.

In this post, we will build a todo application that utilizes a RESTful APIwhich we will also build in the course of this tutorial. I assume you have little knowledge about javascript(es6), reactjs and nodejs. Since we will be using node and npm, you need to install them to your computer, you should also have your favorite code editor already installed.

Table content

  • Node Server Setup
  • Routes
  • Models
  • Database
  • Testing Api
  • Creating the Frontend
  • Running the React App
  • Creating your Components
  • Conclusion

Let’s start with the setup. Open your terminal and create a new file directory in any convienient location in your local machine, and you can name it anything.

mkdir Todo

Enter into that file directory

cd Todo

At this stage we need to initialize our project with a package.json file which will contain some information about our app and the dependencies which our app needs to run. You can use npm init or yarn init and follow the instructions or you can use npm init -yto use the default values.

Don’t worry about the content of my package.json file, because i already installed some dependencies before this post. As we progress into the post, yours will probably end up looking like mine.

Node Server Setup

To run our javascript code on the backend we need to spin up a server which will compile our code. We can create our server in two ways, first is to use the built in http module in node or to make use of express.

For this project we will use express, which is a nodejs framework that handles a lot of things out of the box for us and makes creation of RESTful API a bit simpler. To make use of express, we need to install it using yarn or npm.

yarn add expressornpm install express

Create a file index.js and type the code below into it and save

const express = require('express');
require('dotenv').config();

const app = express();

const port = process.env.PORT || 5000;

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

app.use((req, res, next) => {
  res.send('Welcome to Express');
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`)
});

The code below helps us handle CORS related issues we might face if we try to access our api from a different dormain.

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

It’s time to start our server to see if it works. Open your terminal in the same directory as your index.js file and type

node index.js

If every thing goes well, you should see Server running on port 5000 in your terminal.

Routes

We want to achieve three things with our todo app, which is to create a task, view all task and to delete a completed task. For this, we need to create routes which will define various endpoints that the todo app will depend on. So let’s create a folder routes and create a file api.*_js *_with the following code in it.

const express = require ('express');
const router = express.Router();

router.get('/todos', (req, res, next) => {

});

router.post('/todos', (req, res, next) => {

});

router.delete('/todos/:id', (req, res, next) => {

})

module.exports = router;

Models

Now comes the interesting part, since our app is going to make use of mongodb which is a noSql database, we need to create a model and a schema. Models are defined using the Schema interface. The Schema allows you to define the fields stored in each document along with their validation requirements and default values. In essence the Schema is a blueprint of how the database will be constructed. In addition, you can define static and instance helper methods to make it easier to work with your data types, and also virtual properties that you can use like any other field, but which aren’t actually stored in the database.

To create a Schema and a model we need to install mongoose which is a node package that makes working with mongodb easier.

yarn add mongooseornpm install mongoose

Create a new folder in your root directory and name it models, inside it create a file and name it todo.js with the following code in it.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

//create schema for todo
const TodoSchema = new Schema({
  action: {
    type: String,
    required: [true, 'The todo text field is required']
  }
})

//create model for todo
const Todo = mongoose.model('todo', TodoSchema);

module.exports = Todo;

Having created our model we need to update our routes to make use of the new model.

const express = require ('express');
const router = express.Router();
const Todo = require('../models/todo');

router.get('/todos', (req, res, next) => {

  //this will return all the data, exposing only the id and action field to the client
  Todo.find({}, 'action')
    .then(data => res.json(data))
    .catch(next)
});

router.post('/todos', (req, res, next) => {
  if(req.body.action){
    Todo.create(req.body)
      .then(data => res.json(data))
      .catch(next)
  }else {
    res.json({
      error: "The input field is empty"
    })
  }
});

router.delete('/todos/:id', (req, res, next) => {
  Todo.findOneAndDelete({"_id": req.params.id})
    .then(data => res.json(data))
    .catch(next)
})

module.exports = router;

Database

We need a database where we will store our data. For this we will make use of mlab. Follow this doc to get started with mlab. After setting up your database you need to update index.js file with the following code

const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const routes = require('./routes/api');
const path = require('path');
require('dotenv').config();

const app = express();

const port = process.env.PORT || 5000;

//connect to the database
mongoose.connect(process.env.DB, { useNewUrlParser: true })
  .then(() => console.log(`Database connected successfully`))
  .catch(err => console.log(err));

//since mongoose promise is depreciated, we overide it with node's promise
mongoose.Promise = global.Promise;

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

app.use(bodyParser.json());

app.use('/api', routes);

app.use((err, req, res, next) => {
  console.log(err);
  next();
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`)
});

In the code above we made use of process.env to access the environment variable which we will create now. Create a file in your root directory with name *_.env *_and write

DB = ‘mongodb://:@ds039950.mlab.com:39950/todo’
Make sure you use your own mongodb url gotten from mlab after creating your database and user. Replace ** with the username and ** with the password of the user you created. To work with environment variable we have to install a node package called dotenv which makes sure we have access to environment variable stored in the .env file.

yarn add dotenvornpm install dotenv

Then we require and configure it in our index.js file

require('dotenv').config()

The reason why i choose to adopt using environment variable in our project is that we can hide any sensitive information from our versioning system, so it’s more of security reasons.

Testing Api

This is the part we start trying out things to make sure our RESTful api is working. Since our frontend is not ready yet, we can make use of some api development clients to test our code. I recommend you make use of Postman or Insomnia, if there’s any other client you have, you can still make use of it. Start your server using node index.jsthen open your client, create a get method and navigate to http://localhost:5000/api/todosYou should test all the api endpoints and make sure they are working. For the endpoints that require body, you should send json back with the necessary fields since it’s what we setup in our code.

Creating the Frontend

Since we are done with the functionality we want from our api, it’s time to create an interface for the client to interact with the api. To start out with the frontend of the todo app, we will use create react app to scaffold our app, so we won’t have to worry ourselves with setting up webpack and babel from scratch. In the same root directory as your backend code, which is the todo directory, run create-react-app clientor npx create-react-app client if you don’t want to install create-react-app globally on your computer. This will create a new folder in your root directory called client, where we will be writing all our react code.

Running the React App

After creating the react app, the next thing is to see if the app is well connected and working as well. But before we test it, we need to perform some actions first.

  • Install concurrently as a dev dependency, using yarn add concurrently --dev or npm install concurrently --save-dev. The advantage of concurrently is that it allows us to run more than one command simultaneously from the same terminal window.
  • Install nodemon as a dev dependency using yarn add nodemon --dev or npm install nodemon --save-dev. We will use nodemon to spin up our server and monitor it as well, so that if there is any change in our server, nodemon will restart it automatically for us.
  • Open your package.json file in the root folder of the mern app project, and paste the following code
	{
"name": "todo",
"version": "1.0.0",
"description": "building todo app using mongodb, express, react and nodejs",
"main": "index.js",
"scripts": {
"start": "node index.js",
"start-watch": "nodemon index.js",
"dev": "concurrently \"yarn run start-watch\" \"cd client && yarn start\""
},
"author": "Ojini Jude",
"license": "MIT",
"dependencies": {
"body-parser": "^1.18.3",
"dotenv": "^6.1.0",
"express": "^4.16.4",
"mongoose": "^5.3.6"
},
"devDependencies": {
"concurrently": "^4.0.1",
"nodemon": "^1.18.4"
}
}

  • Enter into the client folder, then locate the package.json file and add the key value pair below inside it. This proxy setup in our package.json file will enable us make api calls without having to type the full url, just /api/todos will get all our todos
"proxy": "http://localhost:5000"

Open your terminal and run npm run dev and make sure you are in the todo directory and not in the client directory. Voila!, your app should be open and running on localhost:3000.

Creating your Components

One of the beautiful things about react is that it makes use of components, which are reusable and also makes ones code modular. For our todo app, we will create two state components and one stateless component. Inside your src folder create another folder called components and inside it create three files Input.js, ListTodo.js and Todo.js.

Open Input.js file and paste the following

	import React, { Component } from 'react';
import axios from 'axios';


class Input extends Component {

  state = {
    action: ""
  }

  addTodo = () => {
    const task = {action: this.state.action}

    if(task.action && task.action.length > 0){
      axios.post('/api/todos', task)
        .then(res => {
          if(res.data){
            this.props.getTodos();
            this.setState({action: ""})
          }
        })
        .catch(err => console.log(err))
    }else {
      console.log('input field required')
    }
  }

  handleChange = (e) => {
    this.setState({
      action: e.target.value
    })
  }

  render() {
    let { action } = this.state;
    return (
      
        
        add todo
      
    )
  }
}

export default Input

To make use of axios, which is a Promise based HTTP client for the browser and node.js, you need to cd into your client from your terminal and run yarn add axios or npm install axios
After that open your ListTodo.js file and paste the following code

	import React from 'react';

const ListTodo = ({ todos, deleteTodo }) => {

  return (
    {todos &&todos.length > 0 ?(todos.map(todo => {return ( deleteTodo(todo._id)}>{todo.action})})):(* No todo(s) left
)}
  )
}

export default ListTodo

Then in your Todo.js file you write the following code

	import React, {Component} from 'react';
import axios from 'axios';

import Input from './Input';
import ListTodo from './ListTodo';

class Todo extends Component {

  state = {
    todos: []
  }

  componentDidMount(){
    this.getTodos();
  }

  getTodos = () => {
    axios.get('/api/todos')
      .then(res => {
        if(res.data){
          this.setState({
            todos: res.data
          })
        }
      })
      .catch(err => console.log(err))
  }

  deleteTodo = (id) => {

    axios.delete(`/api/todos/${id}`)
      .then(res => {
        if(res.data){
          this.getTodos()
        }
      })
      .catch(err => console.log(err))
  }

  render() {
    let { todos } = this.state;

    return(
      
        # My Todo(s)

        
        
      
    )
  }
}

export default Todo;

We need to make little adjustment to our react code, we delete the logo and adjust our App.js to look like this.

import React from 'react';

import Todo from './components/Todo';
import './App.css';

const App = () => {
  return (
    
      
    
  );
}

export default App;	

Then we paste the following code into our App.css file.

.App {
  text-align: center;
  font-size: calc(10px + 2vmin);
  width: 60%;
  margin-left: auto;
  margin-right: auto;
}

input {
  height: 40px;
  width: 50%;
  border: none;
  border-bottom: 2px #101113 solid;
  background: none;
  font-size: 1.5rem;
  color: #787a80;
}

input:focus {
  outline: none;
}

button {
  width: 25%;
  height: 45px;
  border: none;
  margin-left: 10px;
  font-size: 25px;
  background: #101113;
  border-radius: 5px;
  color: #787a80;
  cursor: pointer;
}

button:focus {
  outline: none;
}

ul {
  list-style: none;
  text-align: left;
  padding: 15px;
  background: #171a1f;
  border-radius: 5px;
}

li {
  padding: 15px;
  font-size: 1.5rem;
  margin-bottom: 15px;
  background: #282c34;
  border-radius: 5px;
  overflow-wrap: break-word;
  cursor: pointer;
}

@media only screen and (min-width: 300px) {
  .App {
    width: 80%;
  }

  input {
    width: 100%
  }

  button {
    width: 100%;
    margin-top: 15px;
    margin-left: 0;
  }
}

@media only screen and (min-width: 640px) {
  .App {
    width: 60%;
  }

  input {
    width: 50%;
  }

  button {
    width: 30%;
    margin-left: 10px;
    margin-top: 0;
  }
}	

Also in our index.css file we write the following styling to it.

	body {
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  box-sizing: border-box;
  background-color: #282c34;
  color: #787a80;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}

Assuming we encounter no errors when we saved our code, we should have a working todo app. That has the basic functionality we discussed earlier, which is creating a task, deleting a task and viewing all your task.

Conclusion

A journey of a thousand miles, begins with a step. I believe you’ve taken that bold step towards learning and understanding the MERN stack. Meanwhile i have a little task for you guys. if you’ve noticed, our todo app doesn’t have editing functionality, so i want you guys to do two things; first is to write the api code to implement updating a previous data in the database and secondly is to add two buttons on each task, edit and delete button, so that when as a user, i click the edit button, a popup shows, where i edit that task and save. When you are done feel free to share your github link in the comment, also if you face any issue let’s discuss it as well.

How to Use Express.js, Node.js and MongoDB.js

How to Use Express.js, Node.js and MongoDB.js

In this post, I will show you how to use Express.js, Node.js and MongoDB.js. We will be creating a very simple Node application, that will allow users to input data that they want to store in a MongoDB database. It will also show all items that have been entered into the database.

In this post, I will show you how to use Express.js, Node.js and MongoDB.js. We will be creating a very simple Node application, that will allow users to input data that they want to store in a MongoDB database. It will also show all items that have been entered into the database.

Creating a Node Application

To get started I would recommend creating a new database that will contain our application. For this demo I am creating a directory called node-demo. After creating the directory you will need to change into that directory.

mkdir node-demo
cd node-demo

Once we are in the directory we will need to create an application and we can do this by running the command
npm init

This will ask you a series of questions. Here are the answers I gave to the prompts.

The first step is to create a file that will contain our code for our Node.js server.

touch app.js

In our app.js we are going to add the following code to build a very simple Node.js Application.

var express = require("express");
var app = express();
var port = 3000;
 
app.get("/", (req, res) => {
  res.send("Hello World");
});
 
app.listen(port, () => {
  console.log("Server listening on port " + port);
});

What the code does is require the express.js application. It then creates app by calling express. We define our port to be 3000.

The app.use line will listen to requests from the browser and will return the text “Hello World” back to the browser.

The last line actually starts the server and tells it to listen on port 3000.

Installing Express

Our app.js required the Express.js module. We need to install express in order for this to work properly. Go to your terminal and enter this command.

npm install express --save

This command will install the express module into our package.json. The module is installed as a dependency in our package.json as shown below.

To test our application you can go to the terminal and enter the command

node app.js

Open up a browser and navigate to the url http://localhost:3000

You will see the following in your browser

Creating Website to Save Data to MongoDB Database

Instead of showing the text “Hello World” when people view your application, what we want to do is to show a place for user to save data to the database.

We are going to allow users to enter a first name and a last name that we will be saving in the database.

To do this we will need to create a basic HTML file. In your terminal enter the following command to create an index.html file.

touch index.html

In our index.html file we will be creating an input filed where users can input data that they want to have stored in the database. We will also need a button for users to click on that will add the data to the database.

Here is what our index.html file looks like.

<!DOCTYPE html>
<html>
  <head>
    <title>Intro to Node and MongoDB<title>
  <head>

  <body>
    <h1>Into to Node and MongoDB<&#47;h1>
    <form method="post" action="/addname">
      <label>Enter Your Name<&#47;label><br>
      <input type="text" name="firstName" placeholder="Enter first name..." required>
      <input type="text" name="lastName" placeholder="Enter last name..." required>
      <input type="submit" value="Add Name">
    </form>
  <body>
<html>

If you are familiar with HTML, you will not find anything unusual in our code for our index.html file. We are creating a form where users can input their first name and last name and then click an “Add Name” button.

The form will do a post call to the /addname endpoint. We will be talking about endpoints and post later in this tutorial.

Displaying our Website to Users

We were previously displaying the text “Hello World” to users when they visited our website. Now we want to display our html file that we created. To do this we will need to change the app.use line our our app.js file.

We will be using the sendFile command to show the index.html file. We will need to tell the server exactly where to find the index.html file. We can do that by using a node global call __dirname. The __dirname will provide the current directly where the command was run. We will then append the path to our index.html file.

The app.use lines will need to be changed to
app.use("/", (req, res) => {   res.sendFile(__dirname + "/index.html"); });

Once you have saved your app.js file, we can test it by going to terminal and running node app.js

Open your browser and navigate to “http://localhost:3000”. You will see the following

Connecting to the Database

Now we need to add our database to the application. We will be connecting to a MongoDB database. I am assuming that you already have MongoDB installed and running on your computer.

To connect to the MongoDB database we are going to use a module called Mongoose. We will need to install mongoose module just like we did with express. Go to your terminal and enter the following command.
npm install mongoose --save

This will install the mongoose model and add it as a dependency in our package.json.

Connecting to the Database

Now that we have the mongoose module installed, we need to connect to the database in our app.js file. MongoDB, by default, runs on port 27017. You connect to the database by telling it the location of the database and the name of the database.

In our app.js file after the line for the port and before the app.use line, enter the following two lines to get access to mongoose and to connect to the database. For the database, I am going to use “node-demo”.

var mongoose = require("mongoose"); mongoose.Promise = global.Promise; mongoose.connect("mongodb://localhost:27017/node-demo");

Creating a Database Schema

Once the user enters data in the input field and clicks the add button, we want the contents of the input field to be stored in the database. In order to know the format of the data in the database, we need to have a Schema.

For this tutorial, we will need a very simple Schema that has only two fields. I am going to call the field firstName and lastName. The data stored in both fields will be a String.

After connecting to the database in our app.js we need to define our Schema. Here are the lines you need to add to the app.js.
var nameSchema = new mongoose.Schema({   firstName: String,   lastNameName: String });

Once we have built our Schema, we need to create a model from it. I am going to call my model “DataInput”. Here is the line you will add next to create our mode.
var User = mongoose.model("User", nameSchema);

Creating RESTful API

Now that we have a connection to our database, we need to create the mechanism by which data will be added to the database. This is done through our REST API. We will need to create an endpoint that will be used to send data to our server. Once the server receives this data then it will store the data in the database.

An endpoint is a route that our server will be listening to to get data from the browser. We already have one route that we have created already in the application and that is the route that is listening at the endpoint “/” which is the homepage of our application.

HTTP Verbs in a REST API

The communication between the client(the browser) and the server is done through an HTTP verb. The most common HTTP verbs are
GET, PUT, POST, and DELETE.

The following table explains what each HTTP verb does.

HTTP Verb Operation
GET Read
POST Create
PUT Update
DELETE Delete

As you can see from these verbs, they form the basis of CRUD operations that I talked about previously.

Building a CRUD endpoint

If you remember, the form in our index.html file used a post method to call this endpoint. We will now create this endpoint.

In our previous endpoint we used a “GET” http verb to display the index.html file. We are going to do something very similar but instead of using “GET”, we are going to use “POST”. To get started this is what the framework of our endpoint will look like.

app.post("/addname", (req, res) => {
 
});
Express Middleware

To fill out the contents of our endpoint, we want to store the firstName and lastName entered by the user into the database. The values for firstName and lastName are in the body of the request that we send to the server. We want to capture that data, convert it to JSON and store it into the database.

Express.js version 4 removed all middleware. To parse the data in the body we will need to add middleware into our application to provide this functionality. We will be using the body-parser module. We need to install it, so in your terminal window enter the following command.

npm install body-parser --save

Once it is installed, we will need to require this module and configure it. The configuration will allow us to pass the data for firstName and lastName in the body to the server. It can also convert that data into JSON format. This will be handy because we can take this formatted data and save it directly into our database.

To add the body-parser middleware to our application and configure it, we can add the following lines directly after the line that sets our port.

var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
Saving data to database

Mongoose provides a save function that will take a JSON object and store it in the database. Our body-parser middleware, will convert the user’s input into the JSON format for us.

To save the data into the database, we need to create a new instance of our model that we created early. We will pass into this instance the user’s input. Once we have it then we just need to enter the command “save”.

Mongoose will return a promise on a save to the database. A promise is what is returned when the save to the database completes. This save will either finish successfully or it will fail. A promise provides two methods that will handle both of these scenarios.

If this save to the database was successful it will return to the .then segment of the promise. In this case we want to send text back the user to let them know the data was saved to the database.

If it fails it will return to the .catch segment of the promise. In this case, we want to send text back to the user telling them the data was not saved to the database. It is best practice to also change the statusCode that is returned from the default 200 to a 400. A 400 statusCode signifies that the operation failed.

Now putting all of this together here is what our final endpoint will look like.

app.post("/addname", (req, res) => {
  var myData = new User(req.body);
  myData.save()
    .then(item => {
      res.send("item saved to database");
    })
    .catch(err => {
      res.status(400).send("unable to save to database");
    });
});
Testing our code

Save your code. Go to your terminal and enter the command node app.js to start our server. Open up your browser and navigate to the URL “http://localhost:3000”. You will see our index.html file displayed to you.

Make sure you have mongo running.

Enter your first name and last name in the input fields and then click the “Add Name” button. You should get back text that says the name has been saved to the database like below.

Access to Code

The final version of the code is available in my Github repo. To access the code click here. Thank you for reading !

Build a REST API using Node.js, Express.js, Mongoose.js and MongoDB

Build a REST API using Node.js, Express.js, Mongoose.js and MongoDB

Node.js, Express.js, Mongoose.js, and MongoDB is a great combination for building easy and fast REST API. You will see how fast that combination than other existing frameworks because of Node.js is a packaged compilation of Google’s V8 JavaScript engine and it works on non-blocking and event-driven I/O. Express.js is a Javascript web server that has a complete function of web development including REST API.

Node.js, Express.js, Mongoose.js, and MongoDB is a great combination for building easy and fast REST API. You will see how fast that combination than other existing frameworks because of Node.js is a packaged compilation of Google’s V8 JavaScript engine and it works on non-blocking and event-driven I/O. Express.js is a Javascript web server that has a complete function of web development including REST API.

This tutorial divided into several steps:

Step #1. Create Express.js Application and Install Required Modules
Step #2. Add Mongoose.js Module as ORM for MongoDB
Step #3. Create Product Mongoose Model
Step #4. Create Routes for the REST API endpoint
Step #5. Test REST API Endpoints

Source codes here:
https://github.com/didinj/NodeRestApi...

Fullstack Vue App with MongoDB, Express.js and Node.js

Fullstack Vue App with MongoDB, Express.js and Node.js

In this article, you'll learn building a fullstack Vue note-taking application and showing you how to perform the aforementioned processes, using Node.js running the Express.js framework for the back end, and MongoDB to store our data.

In this article, you'll learn building a fullstack Vue note-taking application and showing you how to perform the aforementioned processes, using Node.js running the Express.js framework for the back end, and MongoDB to store our data.

We learn how to create full fledge application using this increasingly popular tech stack that takes advantage of the upstart Vue.js.

Much of application development, including web applications, has to do with CRUDcreating, reading, updating, and deleting data.

Below is a preview of the application we will be building:

Configuring the Development Environment

For this tutorial, I will be using the Eclipse IDE with the CodeMix plugin installed.

Getting Started

Now we can create our project using the Eclipse IDE, by navigating to File > New > Project. Select the **Vue **option under the CodeMix list of projects, name the application, and click Next to proceed (make sure to be connected to the Internet to enable CodeMix, to get the newest Vue.js template and folder structure for the application), as shown below:

Open the integrated Terminal+ in CodeMix 2.0. Alternatively, it can be opened using the command Ctrl + Shift + P, as shown below:

After that has been completed, we make some changes in the folder structure. First, we add an API folder in the root folder of our project. This folder would contain the Express backend (which includes the server.js file). In the terminal, we run the following commands to install the required modules for the application:

npm install 
npm install --save axios body-parser cors express mongoose moment

  • Axios – a promise-based HTTP client that we will use to communicate with the Node server.
  • Body-parser – a Node.js middleware for parsing request inputs.
  • CORS – middleware that is used to enable Cross-Origin Resource Sharing.
  • Mongoose – an Object Data Modeling (ODM) library for MongoDB.
  • Moment – a library used to parse and format dates.

Next, we add the following line in the scripts object in the package.json file:

...
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "api": "node api/server.js"
  }
...

Running Our Backend and Front-End

Wait, already? Isn’t it too early to run these applications before writing any code? Actually, it isn’t – with the following scripts running, your code will be watched for changes, and the running backend and front-end applications will be automatically updated when necessary.

We can start the Vue.js application using this command in the terminal:

npm run serve

Your browser will automatically open to http://localhost:3000, where you can see the Vue app slowly take shape as we add more code.

And let’s start the back end by using the command below in a different terminal (simply use the +button in the Terminal+ view to open a new terminal tab for the same project):

npm run api

Building the Backend With Node.js and Express.js

Creating the Note Model

Before setting up the actual server, let’s create the Note model, which is the only model for this application. A model is an object representation of the data in a database. Here, using Mongoose we can specify a schema of data as well; this helps with the validation of the data. In the folder, we create a new Note.js file that will contain the code below:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const NoteSchema = Schema(
    {
        title: {type: String, required: true},
        body: {type: String, required: true},
    }, 
    { timestamps: true }
);
const Note = mongoose.model("Note", NoteSchema);
module.exports = Note;

The first parameter object describes the fields, their types, and constraints. The second parameter object of the schema constructor helps create a timestamp, i.e. two auto fields: createdAt which is set at data creation, and updatedAt which is set every time the data is modified.

Creating the Node.js Server

Next up, we create a server.js file in the API folder. This file will contain the Node.js configurations, as well as the routes we will be using in the application. The file will contain the code below:

'use strict';
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const cors = require('cors');
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt');
//models
const Note = require('./Note');
//connect server to mongoDB 
+mongoose.connect(
  'mongodb://localhost:27017/simple_blog', 
  { useNewUrlParser: true, useCreateIndex: true, }
);
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
// retrieves all the notes
app.get('/api/note/list', (req, res) => {
  Note.find({}).sort({updatedAt: 'descending'}).exec((err, notes) => {
    if (err) return res.status(404).send('Error while getting notes!');
    return res.send({notes});
  });
});
// create a new note
app.post('/api/note/create', (req, res) => {
  const note = new Note({body: req.body.body, title: req.body.title});
  note.save( (err) => {
    if (err) return res.status(404).send({message: err.message});      
    return res.send({ note });
  });
});
// update an existing note with the given object id
app.post('/api/note/update/:id', (req, res) => {
let options = { new: true };
  Note.findByIdAndUpdate(req.params.id, req.body.data , options, (err, note) => {
    if (err) return res.status(404).send({message: err.message});
    return res.send({ message: 'note updated!', note });
  });
});
// delete an existing note with the given object id
app.post('/api/note/delete/:id', (req,res) => {
  Note.findByIdAndRemove(req.params.id, (err) => {
    if (err) return res.status(404).send({message: err.message});
    return res.send({ message: 'note deleted!' });
  });
});
const PORT = 5000;
app.listen(PORT);
console.log('api runnging on port ' + PORT + ': ');

The server.js module helps set up a simple connection to MongoDB using a Mongoose method, while also listening for an error event on connecting to the database (which can be caused by improper installation or unavailability of *MongoDB *on the computer). The server.js also applies the necessary middlewares to the *Express server *and provides four routes. The first route fetches all the notes in the *database *using the note model. The second route will allow the creation of a new note. The third route updates a note of a given ID which is passed as the route parameter; it also returns the updated note which, as a result of the options object, is passed to the findByIdAndUpdate method. The last route deletes a note with the ID passed in the parameter of the route.

Building the Front-End With Vue.js

Web Service Calls With Axios

After we have completed the server part of the application, we can proceed to create the repository.js file in the src folder. This file will contain all the server calls we would be making from the Vue.js application using the Axios module. The file code is below:

import axios from 'axios';
const BASE_URL = 'http://localhost:5000';
export function getNotes() {
        return axios.get(`${BASE_URL}/api/note/list`)
                .then(response => response.data);
}
export function deleteNote(id){
        return axios.post(`${BASE_URL}/api/note/delete/${id}`)
                .then(response => response.data)
                .catch(err => Promise.reject(err.message));
}
export function createNote(data) {
        return axios.post(`${BASE_URL}/api/note/create`, 
        { title: data.title, body: data.body }
        )      .then(response => {
                        return response.data
                })
                .catch(err => Promise.reject(err.message));
}
export function updateNote(data, id) {
        return axios.post(`${BASE_URL}/api/note/update/${id}`, { data })
                .then(response => {
                        return response.data
                })
                .catch(err => Promise.reject(err.message));
}

The application is styled using the Bulma CSS framework that is added to the public/index.html file in the head tag, as written below:

<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css">

Creating the Root Component

Next, we proceed to edit the App component, which is the entry component for the Vue.js application. In this file, we add the application header and render a couple of components that we will be building later in this article. The src/App.vue component also provides some methods which manage the application data. This component also loads the list of available notes in the database when the component has been mounted (loaded); it does this using the getNotes function provided in the repository.js module.

If you use CodeMix, you can see below how you will be able to edit the .vue files – these files allow you to keep the HTML, JavaScript, and styles of a component in a single place, and the editor provides content assist and validation corresponding to the section you are in. Have a look at these quick GIFs to see the .vue editor in action.

This App.vue file contains the code below:

<template>
  <div id="app">
    <nav class="navbar is-light" role="navigation" aria-label="main navigation">
      <div class="container">
        <div class="navbar-brand">
          <a class="navbar-item" href="#">
            <span class="title is-size-1">NoteTaker</span>
          </a>
        </div>
      </div>
    </nav>
    <br><br>
    <div  class="container">
      <div v-if="notes">
        <CreateNoteModal @createNote="createNote"/>
        <br>
        <div>
          <noteItem v-for="(note, index) in notes" :note="note" :key="index" @deleteNote="deleteNote" @updateNote="updateNote"/>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import NoteItem  from './components/NoteItem.vue'
import CreateNoteModal  from './components/CreateNoteModal.vue'
import { getNotes }  from './repository'
export default {
  name: 'app',
  components: { NoteItem, CreateNoteModal  },
  data(){
    return {
      notes: []
    }
  },
  methods: {
    deleteNote(id){
      let notes = this.notes.filter(note => note._id != id)
      this.notes = notes;
    },
    updateNote(note){
      this.deleteNote(note._id);
      this.createNote(note);
    },
    createNote(note){
        this.notes = [note, ...this.notes];
    },
  },
  mounted(){
    getNotes()
      .then(data => this.notes = data.notes)
      .catch((err =>alert(err)));
  }
}
</script>

Creating Components

Next, we create the CreateNoteModal component in the src/components/CreateNoteModal.vue, which contains the code below:

<template>
  <div>
    <div class="modal" :class="{ 'is-active': isActive }">
      <div class="modal-background"></div>
      <div class="modal-card">
        <header class="modal-card-head">
          Add Note
        </header>
        <section class="modal-card-body">
          <div class="field">
            <div class="control">
              <input v-model="title" class="input" type="text" placeholder="title">
            </div>
          </div>
          <div class="field">
            <div class="control">
              <textarea v-model="body" class="textarea"  placeholder="enter content">
                </textarea>
            </div>
          </div>
          <button @click="create" class="button is-primary is-pulled-right">Post</button>
        </section>
      </div>
      <button @click="toggle" class="modal-close is-large" aria-label="close"></button>
    </div>
    <button @click="toggle" class="button is-primary is-pulled-right">Create Note</button>
    <br>
  </div>
</template>
<script>
import { createNote }  from '../repository'
export default {
  name: 'CreateNoteModal',
  data(){
    return {
      title: '',
      body: '',
      isActive: false
    }
  },
  methods: {
    create(){
      let data = { title: this.title, body: this.body }
      createNote(data)
        .then(data => {
          this.$emit('createNote', data.note);
          this.title = this.body = '';
          this.toggle();
        })
        .catch(err => alert(err.message));
    },
    toggle(){
      this.isActive = !this.isActive;
    },
  },
}
</script>

This component is a form in a modal with both input in the form, title, and body, bound to the component’s data with corresponding names. The submit button calls the create method which makes the server call, passing the data to the createNote function from the repository.js module. Upon a successful server request, this method emits a custom event that is handled by the parent component (which in this case is the App.vue component). It also clears the form and closes the modal.

Next up, we create the NoteItem component in the src/components/NoteItem.vue, which contains the code below:

<template>
  <article class="message">
    <div class="message-header">
      <p>{{ note.title }}</p>
      <button @click="deleteNote" class="delete" aria-label="delete"></button>
    </div>
    <div class="message-body">
      {{ note.body }}
      <br>
      <br>
      <span class="has-text-grey-light">Created at: {{ note.createdAt | moment }}</span>
      <br>
      <span class="has-text-grey-light">last updated: {{ note.updatedAt | moment }}</span><br>
      <UpdateNoteModal :note="note" @updateNote="updateNote" :key="note._id"/>
    </div>
  </article>
</template>
<script>
  import { deleteNote } from '../repository'
  import UpdateNoteModal from './UpdateNoteModal'
  import Moment from 'moment'
  export default {
    name: 'NoteItem',
    props: [ 'note' ],
    components: { UpdateNoteModal },
    methods: {
      deleteNote(e){
        e.preventDefault();
        deleteNote(this.note._id)
          .then(() => this.$emit('deleteNote', this.note._id))
          .catch(err => alert(err))
      },
      updateNote(note){
        this.$emit('updateNote', note)
      }
    },
    filters: {
      moment(date) {
        return Moment(date).format('MMMM Do YYYY, h:mm:ss a');
      }
    }
  }
</script>

This module renders each note, which is passed to it by its parent component (App.vue). It also provides two methods, the first of which is the deleteNote, which deletes the given note using the deleteNote function from the repository.js by passing the note ID to it. Upon success, it emits a custom deleteNote event to the parent component, which deletes the note from the array of notes.

The second method, updateNode, emits an updateNode event in response to the same event name, emitted by its child component, UpdateNoteModal, which we will create next. It also provides a moment date-time filter using the Moment module to format the date for the component.

Finally, we create the UpdateNoteModal component in the src/components/UpdateNoteModal.vue, which contains the code below:

<template>
  <div>
    <div class="modal" :class="{ 'is-active': isActive }">
      <div class="modal-background"></div>
      <div class="modal-card">
        <header class="modal-card-head">
          Update Note
        </header>
        <section class="modal-card-body">
          <div class="field">
            <div class="control">
              <input v-model="title" class="input" type="text" placeholder="title">
            </div>
          </div>
          <div class="field">
            <div class="control">
              <textarea v-model="body" class="textarea"  placeholder="enter content"></textarea>
            </div>
          </div>
          <button @click="update" class="button is-primary is-pulled-right">Post</button>
        </section>
      </div>
      <button @click="toggle" class="modal-close is-large" aria-label="close"></button>
    </div>
    <button @click="toggle" class="button is-small is-pulled-right">Update</button>
  </div>
</template>
<script>
import { updateNote }  from '../repository'
export default {
  name: 'UpdateNoteModal',
  data(){
    return {
      title: this.note.title,
      body: this.note.body,
      isActive: false
    }
  },
  props: ['note'],
  methods: {
    update(){
      let data = { title: this.title, body: this.body }
      updateNote(data, this.note._id)
        .then(data => {
          this.$emit('updateNote', data.note);
          this.toggle();
        })
        .catch(err => alert(err.message));
    },
    toggle(){
      this.isActive = !this.isActive;
    },
  },
}
</script>

This, much like the CreateNoteModal, is a Bulma styled modal, which has two inputs whose values are bound to the component data, which is initialized using the note passed through to the component as a property. It also provides an update method, which is called when the post button is clicked. This method uses the updateNote function from the repository.js module to update the note. Upon a successful request, it emits an event – the updateNote event, which is handled by the parent component (i.e. the NoteItem component, which further passes it to the App component).

We did it, our note taking app is complete! Remember, if you haven’t already run your backend and front-end applications, please scroll back to the Running our Backend and Front-End sections for instructions.

Next Steps

To keep focused on the concepts being demonstrated, we’ve developed a simplified application. Here are some additional steps that would take our application to the next level:

  • Add authentication – Although the application performs the basic functions of a note-taking application and the four fundamental **CRUD **operations, it does not perform any form of authentication.
  • Folder structure – The folder structure is not suitable for larger applications, for example, the routes are usually in a separate file from the server configuration, and the models are usually grouped in a folder.
  • Vuex – Better stage management is possible by using a framework like Vuex.

The code for this application can be downloaded here.