Containerized ExpressJS service in 10 mins or less
Tags: express, javascript, docker, node
Published: 2020-01-06 02:25:30

# Intro 

Yah this article has probably been written 100 times across different blogs. However there are two reasons why I am writing it: 

1.) I'm trying to get into blogging and sharing my knowledge this year. 

2.) I am trying to make this something a complete beginner could follow,and be running in 10 mins or less.      


**So what are we going to build here**

We will be setting up a simple NodeJS server (powered by ExpressJS). 
This server will support a API, along with a view engine for rendering some pretty things to the browser. Finally, we will wrap our application in a Docker container allowing easy hosting in a service like AWS. 

# Glossary (list of tools and concepts you need to know) 

[NodeJS](https://nodejs.org/en/)
A javascript runtime that allows javascript code to be written and executed outside of a browser. It come with a set of standard utility libraries for handling file system operation, compression, and other low level tasks. It allows us to build backend servers in Javascript.   


[ExpressJS](https://expressjs.com/)
A popular web framework that runs on top of NodeJS. It handles HTTP calls, routing, views, etc. Basically it abstracts away some of the low level stuff so that we can focus on building websites. 


[Docker](https://www.docker.com/)
This is a popular software for running containers. Containers are operating systems that run as a virtualized instance on your machine (or on a cloud host). Since the docker environment is decoupled from your host machine, you have confidence that your software will run the same anywhere you decide to put it. 

# Step1: Setting up a ExpressJS server

First you will need to install NodeJS. If you are on OSX, the easiest way to do this is via a package manager like [Homebrew](https://brew.sh/). This allows you open your terminal and run 

`brew install nodejs`

otherwise just install it manually from [here](https://nodejs.org/en/). 

Once node is setup we can bootstrap our ExpressJS project. The easiest way to do this is to use a tool called [express-generator](https://expressjs.com/en/starter/generator.html). 

Install this as a global node package using

`npm install -g express-generator`.

Once that finishes we run a command to setup our project

`express --view=ejs my-app`

This sets up a new express app, using the [EJS](https://ejs.co/) view engine. Putting it into a folder called my-app. 

Navigate to the my-app folder and run 

`npm install`

This will parse the package.json and install an necessary dependencies. 

With this you should be able to type 

`npm run start` 

Navigate to http://localhost:3000 to see your app. By default there are two routes active. 

http://localhost:3000 -> Index/Title Page 
http://localhost:3000/users -> A api page that returns a mock resource. 

Im not going to go in depth here on how to build a full application here. Feel free to explore/experiment with this: 

app.js -> This is your server entry point. High level route registration, and middleware injection happens here. 

views/ -> this folder holds your UI templates 
routes/ -> this holds the javascript route controllers. They tell your server what to do when a user tries to hit a specific page 
public/ -> This holds your static assets CSS/Javascript/Images 

# Step 2: Running above code in Docker

First we need to install docker. Unfortunately this is a rare case where its actually more annoying to use Homebrew than it is to just get the software from the official website. Download [here](https://www.docker.com/get-started). 

Once you have Docker installed we need to make 2 files in our `/my-app/ `directory.  

1.) Create a `.dockerignore` file and the following lines
```
node_modules
npm-debug.log
```

this prevents docker from packaging our dependencies. It will download those itself, using npm, 

2.) Next create a file called `Dockerfile` at the root of `/my-app/`
Read the comments here if you are curious what each line means 
```
# We import our base operating image. In this case I use node:12 
# as that is the most recent stable release of NodeJS
from node:12


# Create a directory where your app will run, inside the docker environment
WORKDIR /usr/src/app

# Copy package.json and package-lock.json these are your depedency definitions 
COPY package*.json ./

# Install your dependencies 
RUN npm install 

# Copy your application into the container directory 
COPY . . 

# Expose whatever port your application is running on. 
# In this case it is port 3000
EXPOSE 3000

# Start our application
CMD ["npm", "run", "start"]
```

With this we have defined what our Docker container will do. Now it is time to build it. Run the following while in the directory where your Dockerfile is located: 

`docker build -t my-app-container .`

This will execute the above Dockerfile. Setup all dependencies, and build a executable image. 

once this is complete run 

`docker images`

you should see something like this:

```
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
my-app-container    latest              c4f59b39a747        9 minutes ago       915MB
node                12                  6b5991bf650f        8 days ago          913MB
``` 

Now to run your app in the container you can run this command: 

`docker run -p 8080:3000 my-app-container`

This command runs the images, and forwards traffic from the internal docker port (3000 where our app is running), to the local port 8080. 

With this you should be able to navigate to http:localhost:8080, and see the express app running. 

# Conclusion 
That it you now have a express app setup, and a portable Docker container. You can run this container locally, put it on a service like Amazon ECS, Digital Ocean, Azure, Google Container Service. Or just give it to a friend, and you will be sure that it runs exactly as on your machine. 

# Next Steps 

Of course the app we made is far from production ready. There are a couple things we could do to improve the overall architecture here. For example. 

1.) Add a NGINX layer for to act as a load balancing production server. 

2.) Add Supervisor to auto restart our app process on failure.

3.) Add Typescript to express for type safe code. 

4.) Serve a ReactJS bundle on one of our routes. 

5.) Deploy our app to a cloud provider like Amazon ECS 

6.) Add nodemon to speed up our development workflow. 


Comment if any of these would interest you in future tutorials.