Simple Dockerized CRUD Node.js Web App & Unit Tests

Burak Ergören
Sahibinden Technology
8 min readFeb 8, 2022

In this project, we will create a simple authorized login panel using Node.js & Express for backend, Pug for view, MongoDb Atlas for database, Passport for authentication and we will test it using Mocha and Chai. We also visualize our APIs using Swagger and lastly containerize the project using Docker.

You can reach the source code from here. In this article, we will proceed based on this project.

Let’s get to know the technologies we use:

Node.js is an open source, cross-platform Javascript runtime environment for developing server-side and networking applications.

Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

Pug is a template engine to convert the injected data and translate it into html syntax.

MongoDB is a document database with the scalability and flexibility that you want with the querying and indexing that you need. MongoDB Atlas is a multi-cloud database service by the same people that build MongoDB.

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

Passport.js is authentication middleware for Node.js.

Swagger is a tool that can help you design, build, document and consume REST APIs.

Docker is an open platform container technology for developing, shipping, and running applications

Project Development Steps

  • Getting started / set up
  • CRUD Rest API
  • Swagger API visualization
  • Login/Authorization Panel Web App
  • Mocha Unit Test
  • Dockerize Project

Step 1: Getting started / project set up

  • I assume that node is already installed. (check with “node -v” command)
  • Create a project directory and make it your current directory
  • Execute “npm init” command. Fill in the requested information. It will create “package.json” file which stores dependencies for the project.
  • Next step, we need to install Express with command
    npm install express -- save
  • This command will install express library and save the dependency to package.json file with “--save” command flag. So we can install all these dependencies later just running “npm install” command. Now package.json file should look like :
  • After installing express module, we are ready to use it. In the main file
    (I named it as server.js) this app starts a server and listens on port 3000 for connections. The file looks like;
  • When we run the application with “node server.js” command, the app responds with server log on the console and requests to the root url.
  • Request will respond with message like below. For every other path, it will respond with a 404 Not Found error.
  • So we are ready to use our server, everything looks fine.
  • For CRUD system we need database connection. In this project, we use MongoDB Atlas for database. We need a connection string to use this cloud db in our project. You can follow the set up steps from here.
  • ( P.S. If you download the project from github and run it directly, you will get an error message when connecting to the database. You must define your personal db connection to the project.)
  • After getting the connection string, it’s time to set up database connection. We need to install “mongoose” (again we need to run command like npm install mongoose -- save for each needed module. I will not repeat this in the rest of the article.)
  • Now we can create our database config file. In the project folder, create new folder “config” and new file like “db.config.js”
  • We already have the MongoDB connection string, it’s time to use it as parameter for mongoose and this is how we can do :

Step 2: CRUD Rest API

  • Now, we are ready to implement CRUD Rest api.
  • CRUD is an acronym for Create, Read, Update, and Delete. These are the four basic functions that models should be able to do.
  • CRUD is also appears in discussion of RESTful APIs. Each letter in the acronym mapped to HTTP method:
https://www.slideshare.net/FxDataLabs/rest-api-andcrudapi
  • For modular node.js project structure, the logic should be divided into these directories and files.

Models — The schema definition of the Model

Routes — The API routes maps to the Controllers

Controllers — Handles all the logic behind validating request parameters, query, sending responses..

Services — Contains the database queries and returning objects or throwing errors

  • The diagram below is the main flow of data when handling an HTTP request/response for node.js/express projects.
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes/mvc_express.png
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes/mvc_express.png

So let’s start coding. We have to define a schema before creating documents and saving them to the database. First, create the models directory and then create a file called user.js be like models/user.js.

Now, let’s create a schema in user.js file:

Our user model schema will have a name, an email address and a password field. So all of the users will have the data in this format.

We use “mongoose-unique-validator” module to make the email parameter unique.

Now, we will define our controllers. Create “controllers” folder and user.controller.js file.

We want that our api can do these jobs:

  • Retrieve a list of users : findUsers
  • Retrieve a single user by id: findUserById
  • Retrieve a single user by name: findUserByName
  • Create a new user : createNewUser
  • Edit user by id : updateById
  • Edit user by name: updateByName
  • Delete user by id: deleteUserById

Let’s start coding for controllers. First we define our User model variable and develop it for needs based on api. Example coding for findUsers and createNewUser functions is like below (you can check other functions on github)

Next step we will describe the routes. Create the “routes” folder and user.routes.js file like “routes/user.routes.js”

Describe the related paths and parameters like below :

Last step, db.config and user.routes improvements need to be defined in our server.js main file :

Finally our node.js CRUD Rest API is ready. Next step we will visualize it using swagger.

Step 3: Swagger API visualization

  • To use swagger, we need to install swagger-jsdoc and swagger-ui-express modules.
  • Then we need to develop swagger configuration file.
  • Create a new file “swagger.config.js” in configuration folder. We need to specify fields like title, description, contact etc. The implementation should look like :
swagger config
  • So our config file is ready. Now we will implement swagger integration in user.routes.js file.
  • We need to specify the properties like summary, description, item types, example usages etc.
  • For example, for “/getUsers” endpoint the implementation should look like
  • In the next step, swagger definition should be added for other endpoints as in the example above.
  • Lastly, we need to define our swagger configuration in our server.js file.
  • When we call “/api-docs” endpoint, swagger UI will display and it will be ready to use our API.
  • So swagger UI is ready. When we call “http://localhost:3000/api-docs” screen will look like below.
  • We can do all CRUD operations for our web service using this UI.

Step 4: Login/Authorization Panel Web App

Now, it’s time to develop login panel web app. We will develop in two stages, frontend and backend.

1. Frontend

  • This app will have 2 webpages; login and welcome.
  • We will basically use this ready html template in our project.
  • We need to convert this html template to pug.js
  • Lets create “views” folder and new files login.pug, welcome.pug
  • Login.pug will be the opening page. There will be login and register functions.
  • By default, login form will appear. When we click register button, register form will appear.
  • After successful register, login form will appear again.
  • When we login successfully welcome page will be opened and it will show our username data as welcome message.
  • So the login page coding will be like:
  • And welcome page coding will be like:
  • Then create “public/css/style.css” and “public/js/main.js” files. In these files, we will specify how the design and actions of our login/register web page should be.

2. Backend

  • In this stage, we will provide directions with button actions on the login page.
  • When we click register submit button with filled username, password and email fields, post request will be called.
  • In register function, we use bcrypt.js module to hash password
  • Successfully registered user data will be saved in MongoDb.
  • Then we go to the login stage. At this stage, we check that the entered user information and the user information in the database are the same. For this authentication we use passport.js
  • So let’s start for coding, first we need to add auth.config.js:
  • Other parts of code development will be done in server.js file. The final situation in the file is like:
  • So development is done and we are ready to use web app.

Step 5: Unit Testing with Mocha & Chai

  • Let’s add unit tests to our project. We will use Mocha as testing framework and Chai as assertion library. First, we need to install these modules.
  • Then, we should refactor test script configuration in package.json file like;
  • Now, we are ready to develop unit tests.
  • There will be beforeEach and afterEach steps to prepare mock data at the beginning of each test and clean it at the end of the test.
  • Mocha “describe” function encapsulates our expectations.
  • Mocha “it” function is also like describe. In this function, we must use our expectations in the body.
  • So the example coding for /getUsers endpoint is like below. You can add unit tests for remaining api requests based on this example.
  • Now, its time to run unit tests.
  • Go to the terminal and open the project folder. Then run the test script command that we defined earlier “npm test”
  • The results will look like below:

Step 6: Dockerize Project

  • At last step, we will use docker to containerize our project.
  • In this way, we will be able to run the app without installing any project bindings.
  • So we will create a Dockerfile to define instructions and a docker-compose.yaml file to create and run the service with a single command.
  • In Dockerfile; we need node image to run our node.js web app. We need to install all related modules in the project so we should read package.json file. We need to define port number for service and finally we should define npm start command. So Dockerfile should look like;
  • Now, we will create docker-compose.yaml file. This is the simple instructions for our yaml file:
  • Finally we are ready to run our app using docker.
  • In the project root folder, just running “docker compose-up” command is enough. Docker will do the rest.. Our web app will be running on http://localhost:3000

Aaaaandd, our project is ready :) Thanks for reading. Hope you liked the article. I want to remind again, you can check the source code from here.

See you in other posts!

--

--