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.
- Open up a terminal/command line and run:
- 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 viarequest.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
andmodel
as parameters when instantiated - Binds onto the view or model
- instead of using
.bind
I used arrow functions since they preservethis
- instead of using
- 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
- Accepts the
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:
- The MongoDB container via Docker
- The Web API
- The front-end