Simple Web API & Client

Express, Node.js, MongoDB, JavaScript

Posted by Yasthil Bhagwandeen on October 01, 2019 · 8 mins read

Background

The language of the web is JavaScript and being fluent in it will only come with practice. Majority of my background has been in the gaming realm and mainly focused around Unity and C# building prototypes with no restrictions in mind. However, in the web world, one doesn’t have all the resources compared to a natively running game/app. Since I’ve been using a lot of JavaScript and Typescript at work, I decided to expand my knowledge using some tech I haven’t tinkered with before.

Goals

Create a simple, end-to-end web application that encorporates your typical client and server tech stack. In short, build a CRUD app - the world famous Todo list app

Front-end:

  • Super simple, vanilla JavaScript
  • Use async/await or Promises for asynchronous operations
  • MVC design pattern

Back-end:

  • NodeJS
  • Express server
  • MongoDB + Mongoose
  • MVC design pattern

Development

Tools and products used:

  • GitLab
  • Cmder
  • Visual Studio Code
  • Docker

Visual Studio Code extensions:

  • jshint
  • Beautify
  • Debugger for Chrome
  • Bracket Pair Colorizer
  • Docker

Back-end:

I followed this as a reference as it very neatly laid out the basics and structure of exactly what I wanted to build. I’ve made the following changes/additions:

  • Specifying a CORS policy
  • Detailed comments to help my understanding
  • Removed hard-coded strings and replaced them with a Constants class
  • Removed duplicate code
  • Used a Docker container to run MonoDB instead of installing it locally
  • Used JSHint for linting

Setting up MongoDB:

MongoDB is a documented based (JSON) distributed database built for modern apps and popular in the web realm. It was lightweight and easy enough to get start with. Instead of opting to install it on my PC - I decided to use the mighty Docker instead! I’ve recently fell in love with Docker after using it to set up an ownCloud instance, a few nginx containers and traefik (for reverse proxying).

  • Step 1: Install Docker Desktop for your Windows/OSX/Linux
  • Step 2: Find the MongoDB official image on Docker Hub

  • Step 3: You would have noticed there’s various images for many different versions of MongoDB, we can choose 3.4-xenial:
    • Open up a terminal/command line and run:
        docker run --name restful-api-mongo -d -p 27017-27019:27017-27019 mongo:3.4-xenial
      
    • Let’s understand what’s going on in that one line:
      • --name restful-api-mongo - create a new container restful-api-mongo
      • -d - run in detatched mode (i.e. it will run in the background even after you close the terminal window)
      • -p - specifies which port we want to map to: The mapping is as follows: HOST_PORT:CONTAINER_PORT, hence we’re mapping the range 27017-27019 from the host machine (your computer that you’re using) to the container’s port 27017-27019.
      • mongo:3.4-xenial - specifying the image name (mongo), and it’s version (3.4-xenial)
    • Docker will then pull the image (if it’s not already cached on your machine), then start it. If it was successful, you should just see the container id displayed.
  • Step 4: Run docker ps - and you should see something like this:

Now that Mongo is setup and running, I can now start our webserver.

Project structure:

Since we’re using an MVC pattern, the classes are separated accordingly:

  • todoListController.js:
    • Central controller that provides the functionality by making use of the view and model. It contains the functions that will retrieve the data from the model and process them accordingly.
  • todoListModel.js:
    • We’re making use of Mongoose, which gives us neat MongoDB object modeling.
    • Contains the Schema - which is the allows us to do JSON schema validation
  • todoListRoutes.js:
    • Defines the specific routes for each operation
    • The instance of express is passed to it so it can set these routes on it using .route
  • constants.js:
    • Contains contants used throughout code
  • server.js:
    • Entry point to API
    • Defines the CORS policy
    • Connects to Mongo via Mongoose
    • Make use of bodyParser which we use for parsing incomming requests bodies in middleware before the handlers. Thus allowing us to access the body via request.body
    • Starts the express server

Front-end:

Keeping it simple and focusing only on the basic CRUD operations I used plain JavaScript for the font-end. Used this as a starting point.

Asynchronous operations:

Since we’ll be fetching data from the server via the Web API - we’d need to do this in an asynchronous manner - i.e. when we request something, the response is not be instanteous - thus we must rather wait for the response to come back and handle it once it’s returned.

I looked at the differences between async/await vs Promises and opted for promises. I did later read in this article that async/await out performs Promises. Perhaps I’ll try using async/await in the next project.

I made use of the fetch API to handle all requests sent to the webserver.

Project Structure:

  • controller.js:
    • Accepts the view and model as parameters when instantiated
    • Binds onto the view or model
      • instead of using .bind I used arrow functions since they preserve this
    • Serves as main controller between the model and view
    • Data passed down to the view/model, and it listens for events coming up from them
  • model.js:
    • Handles all operations related to the model (data) from the back-end.
    • Maintains an array with all the task records from the server
    • Uses a helper, db.js, to facilitate all calls
  • task.js:
    • Meant to serve as the model (type) which is a representation of each record, however I’ve not used it yet.
    • *This will be used in the future perhaps - when I convert this project into TypeScript
  • constants.js:
    • Stores all constants
  • db.js:
    • Provides functions to interact with the API
    • This is where the actual fetch API calls are performed
  • view.js:
    • Responsible for all DOM interactions
    • Binds functions to controller
    • Acts on data it receives from the controller
  • app.js:
    • Entry point for the client

Usage

Start the following in this order:

  1. The MongoDB container via Docker
  2. The Web API
  3. The front-end

Result