Learn RestFul API with NodeJS and MongoDB

Back-end

As a modern developer it is worth knowing what is Restful API and how to write one. In this article I will take you through the full process of creating a Restful API using the most dominant technologies that are trending in web development today most prominently  NodeJS and MongoDB. We will build a traditional CRUD Restful API of a simple Todo Application.

Yeah, if you are new here, I will recommend you to first go through this article that actually shows how to build intuitive UI design with angular and angular-material-design of this app. For consistency, we will continue the development of the same app with the backend part today and probably the api integration in our article of the next week.

 

What is a Restful API?

REST (Representational State Transfer) is the underlying architectural principle of the web. The amazing thing about the web is the fact that clients (browsers) and servers can interact in complex ways without the client knowing anything beforehand about the server and the resources it hosts. The key constraint is that the server and client must both agree on the media used, which in the case of the web is HTML.

An API that adheres to the principles of REST does not require the client to know anything about the structure of the API. Rather, the server needs to provide whatever information the client needs to interact with the service.

 

App refactoring (not mandatory if you just want to learn API development)

If you actually followed the article on learning angular 7 by building a todo app, you should have noticed that the creation of a todo require only one text input field which takes the description of the todo. Let's refactor our code to make our app more useful by adding two input fields instead of one. We can have a text field for the title and then another field textarea for the description of the task todo. We'll have a couple of files to touch here, let's start by changing our html code to add the two fields. open the file app/addtask/addtask.component.html and change its content to reflect the snippet below:

<h2 mat-dialog-title>Add a new todo</h2>
 <mat-dialog-content>
    <mat-form-field class="example-full-width">
      <input matInput placeholder="todo Title" [(ngModel)]="data.title" #data="ngModel" >     
    </mat-form-field>
    <mat-form-field class="example-full-width">
      <textarea matInput placeholder="todo description" [(ngModel)]="data.description" #data="ngModel"></textarea>
    </mat-form-field>
 </mat-dialog-content>
 
 <mat-dialog-actions>
  <button mat-button (click)="onCancel()">Cancel</button>
  <button mat-raised-button color="primary" (click)="onSave(data)">Save</button>
 </mat-dialog-actions>
 

As you can see the main updates concern the mat-dialog-content section and the we also change the ngModel to pass an object called data.

Next open your app/addtask/addtask.component.ts to update your onSave() method to pass an object as the second argument:

onSave(data): void {
    this.myData.addTodo(this.lastId+1, { 
       title: data.title, 
       description: data.description
    });
    this.dialogRef.close();
 }
 

Then we go into our service app/todo.service.ts to update the initial todo array variable and update the addTodo() method to reflect the following:

//todo array variable
 todos: any[] = [
    {
        id: 1, 
        title: 'Hello World!', 
        description: 'welcome to programming concept'
    }
  ];
 
 //add todo function
 addTodo(id:number, data:any, ){
    return this.todos.push({id: id, title: data.title, description: data.description});
 }
 

Finally, we update our listing page to also display the title and the description of each todo list. Open app/tasks/tasks.component.html and change its content to this:

<mat-list>
  <h3 mat-subheader>Today</h3>
  <mat-list-item *ngFor="let todo of todos">
    <mat-icon mat-list-icon>watch_later</mat-icon>
    <h4 mat-line>{{todo.title}}</h4>
    <p mat-line> {{todo.description}} </p>
    <span style="position:relative; right: 35x">
          <button mat-button [matMenuTriggerFor]="menu">
              <mat-icon mat-list-icon>more_vert</mat-icon>
          </button>
          <mat-menu #menu="matMenu">
            <button mat-menu-item>Edit</button>
            <button (click)="deleteItem(todo.id)" mat-menu-item>Delete</button>
          </mat-menu>
    </span>
    <mat-divider></mat-divider>
  </mat-list-item>
 </mat-list>
 

If you were curious enough, you will have seen that we added a new material design component called mat-menu and to make this work we have to import the menu module in our app.module.ts file:

//inject the module
 import {..., MatMenuModule} from '@angular/material';
 //import array
 imports: [
    ...,
    MatMenuModule
 ],
 

That is all, and your code is now updated and should look like the following image:

 

RestFul API Pre Requirements

We are going to build everything from scratch in other to learn more because there are scaffolding tools we can use to generate a seed starter api app for nodejs and mongodb.

NodeJS will be used as our server side language and to run node code you need to have it installed on your computer. You can read the installation part on my previous article that will walk you through. If that is done, the next step will be to install mongoDB for our data storage. It's pretty easy to do that, all you have to do is to go to their official website and follow the instructions depending on your Operating System. And finally to ease the manipulation of these within our code we will need to install a couple of node packages such as: express, body-parser, mongoose, cors, and nodemon.

 

Setting up our Restful API application

Assuming you have node and mongodb installed, let's start by creating a folder called /todo-api-app and inside this we create a file called app.js and a folder for our models called /models.

Now, let's create our node package file. we will run the following npm command and answer the question by typing them and pressing enter or just press enter if we want to choose the default answer.

$ npm init

After this we should have our package.json file created.

We are good to go now, let's install all our dependencies by running the following commands one after another:

$ npm install express --save
 $ npm install body-parser --save
 $ npm install mongoose --save
 

That is all.

 

Our first  line of code for the RestFul API

Let's write our "hello world" app with node and mongodb and connect it to our mongo database. Here is how the code look likes:

const express = require('express');
 const app = express();
 
 const bodyParser = require('body-parser');
 const mongoose = require('mongoose');
 
 // connect to our mongo db
 mongoose.connect('mongodb://localhost/tododb');
 const  db = mongoose.connection;
 
 
 //then we create our first resource
 app.get('/', function(req, res){
    res.send('Hello World!');
 });
 
 app.listen(3000);
 console.log('sever running on port 3000');
 

To test your app, go into your terminal and navigate you /todo-api-app folder and run the following command.

$ node app.js

If it shows the string "server running on port 3000" then, that is good you can now open your browser and navigate to http://localhost:3000 to see the "Hello World" response from your server. Now, let's change our "Hello World!" string to "Welcome to my app" save and refresh your browser. Ooops no change you have to stop you server with the CTR+X or Control+X then re run the node app.js to start it back before it works.

 

Avoiding restarting the server

It will be good to also install a live serve that will be automatically reloading our serve when ever we made some changes on our code. Let's do it with this command:

$npm install -g nodemon

Yeah, we added the -g flag to tell npm to install it globally so that we can use it everywhere without reinstalling it. You can now just start you server by running this command:

$ nodemon app.js

Now, try making changes you will see that the server is refreshing automaticaly right ? that is great.

 

Let's create our database

It's time now to respond to our request with data from the mongo database. Let's go and run our mongodb, mine is in a /data folder just navigate to it and run mongo as shown on the figure below.

Explanaition: 

1- we start the mongodb engine to be able to write our mongodb commands. When it's started, we can see all the databases with the following command: $ show dbs

2- now, we create our database with a simple use tododb command where tododb is the name of our database: $ use tododb

3- after that we create a collection to store our todos list with the following createCollection() command: $ db.createCollection(“todos’)

4- To see the list of collections(equivalent of tables in a RDBMS) in our database run this: $ show collection

5- Finally, one last thing to do will be to insert one record into our collection so that we can send that as response with our node code.

$ db.todos.insertOne({title: “Api integration”, description: “next week article on api integration with angular 7”})

$ db.todos.fond() //to see the list of documents in a collection.

 

Creating our Todo Schema with the differents resources methods

Now, go into your models folder and create a file called todo.js and add the following code snippet:

const mongoose = require('mongoose');
 
 // Todo Schema
 const todoSchema = mongoose.Schema({
     title: {
         type: String,
         require: true
     },
     description: {
         type: String,
         require: true
     },
     created_at: {
         type: Date,
         default: Date.now
     },
     updated_at: {
         type: Date,
         default: Date.now
     }
 });
 
 //export our Todo model
 const Todo = module.exports = mongoose.model('Todo', todoSchema);
 
 //here we add the getTodos method and export it to our model
 module.exports.getTodos = (callback, limit) => {
     Todo.find(callback).limit(limit);
 }

You can see inside the getTodos method that we access directly the find() and limit() methods of mongodb through our Todo model. We are passing our callback function here to make sure that it works asynchronously.

 

Creating the api/todos route to get all the todos

Creating the api/todos route to get all the todos in your app.js file is actually simple. To do that we inject our Todo model and directly access the getTodos method as shown below.

//route to handle the get todos list
 app.get('/api/todos', (req, res) => {
     Todo.getTodos(
         (error, todos) => {
             if(error){
                 throw error;
             }
             res.json(todos);
         }
     );
 });

 

Creating the api/todos/:_id route to get a single todo

The only thing to add here is that we get the parameter from the params object of the req object and also at the Model level we use a new mongodb method called findById() to get a todo by his id. Here is the code snippet:

The Model method:

//here we add the getTodoById method and export it to our model
 module.exports.getTodoById = (id, callback) => {
     Todo.findById(id, callback);
 }

And the routing code:

//route to handle the get a single todo
 app.get('/api/todos/:_id', (req, res) => {
     Todo.getTodoById( req.params._id,
         (error, todo) => {
             if(error){
                 throw error;
             }
             res.json(todo);
         }
     );
 });

 

Creating the api/todos route to add a new todo

Now, that we want to add a new todo the request type should change to post, also we have to pass the content the body of our request. This is where the body-parser package comes into the game. So you have to do this like of code at the top section of you app.js file directly after all the injected files and packages.

app.use(bodyParser.json());

Then, our model code should look like this:

//here we add the addTodo method and export it to our model
 module.exports.addTodo = (todo, callback) => {
     Todo.create(todo, callback);
 }

And in our routes side we have this:

//route to handle the add todo
 app.post('/api/todos', (req, res) => {
     let todo = req.body;
     Todo.addTodo( todo,
         (error, todo) => {
             if(error){
                 throw error;
             }
             res.json(todo);
         }
     );
 });

To see this in action all we need to do is to use an API Development Environment tool like Postman. If you don’t have it yet you can download your corresponding version and install it on you computer. Then, just send a post request to your server started with the nodemon app.js command. This is how it looks like :

Note: you have to switch the Headers tap to add this key/value pair (Content-Type/application/json) otherwise the request body will not be send.

 

Creating the api/todos/:_id route to update a todo

Here, we want to update an existing todo. The request type should be change to put, also we have to pass the content the body of our updated request. Yeah,  as you may guess, we pass three parameters to our method now (the id, the body content to change, and the callback function). Below is the code snippet of our update model:

//here we add the updateTodo method and export it to our model
 module.exports.updateTodo = (id, todo, callback) => {
     let query = {_id: id};
     let update = {
         title: todo.title,
         description: todo.description
     };
     Todo.findOneAndUpdate(query, update, callback);
 }

One new thing we can realize here is that we are using a new method findOneAndUpdate(). At our routing side, we have the following:

//route to handle the edit todo
 app.put('/api/todos/:_id', (req, res) => {
     const id = req.params._id;
     const todo = req.body;
     Todo.updateTodo(id, todo, 
         (error, todo) => {
             if(error){
                 throw error;
             }
             res.json(todo);
         }
     );
 });

As simple as that...

 

Creating the api/todos/:_id route to delete a todo

Finally, we are here, now we want to delete an existing todo. the request type should be change to delete(), and we pass the id of the todo to delete along with our request. All we will have to use here is the remove() method of the Todo model as shown below:

//here we add the deleteTodo method and export it to our model
 module.exports.deleteTodo = (id, callback) => {
     let query = {_id: id};
     Todo.remove(query, callback);
 }

Then, our routing code is as follows too:

//route to handle the delete todo
 app.delete('/api/todos/:_id', (req, res) => {
     const id = req.params._id;
     Todo.deleteTodo( id,
         (error, todo) => {
             if(error){
                 throw error;
             }
             res.json(todo);
         }
     );
 });

Great, you have crossed the most difficult part. Now, you have the basic understanding of RestFul API with NodeJS and MongoDB even though there's still much to learn, this was a good start. If you liked this please share it and leave a comment on a topic you will like to see next.

 

You can share this post!

bproo user profil

Kamdjou Duplex

the world would not be so beautiful without people willing to share knowledge