Express Application with MongoDB
Build an Express Application that uses MongoDB and Docker
Contents
- Setting up Mongo
- # Adding Mongo to your PATH
- # Create a Data Directory
- # Running the DB Server
- # Creating and Viewing Elements
- # Connect to a Database
- # Insert Data
- # View Data
- Building the Express App
- # Importing the Necessary Libraries
- # Configure the Database
- # Middleware
- # View Comments
- # Creeate Comment
- Deploy on k8s
- # Building the Image
- # Deploying on Kubernetes
- Running Locally
Built with tons of help from:
Setting up Mongo
# Adding Mongo to your PATH
If you have just downloaded and installed MongoDB, it may not be defined as a system variable in your PATH, you can do that finding the Mongo installation directory and adding this as a system environment variable, the directory should be like the following for Windows
C:\Program Files\MongoDB\Server\4.0\bin\
This will give us access to both mongo
and monod
commands
# Create a Data Directory
Next we will need a place to store our data, we can create this directory anywhere we want, in this case I'll make it inside of my app directory
mkdir mongodata
cd mongodata
mkdir data
# Running the DB Server
Next we can run our database server with the following command inside of our mongo
directory that we just created
mongod --dbpath .\data\
If we see an output with
...
2018-12-21T09:01:21.883+0200 I NETWORK [initandlisten] waiting for connections on port 27017
2018-12-21T09:01:21.928+0200 I INDEX [LogicalSessionCacheRefresh] build index on: config.system.sessions properties: { v: 2, key: { lastUse: 1 }, name: "lsidTTLIndex", ns: "config.system.sessions", expireAfterSeconds: 1800 }
2018-12-21T09:01:21.928+0200 I INDEX [LogicalSessionCacheRefresh] building index using bulk method; build may temporarily use up to 500 megabytes of RAM
2018-12-21T09:01:21.936+0200 I INDEX [LogicalSessionCacheRefresh] build index done. scanned 0 total records. 0 secs
We know that the server is running
# Creating and Viewing Elements
In a new terminal window we open the Mongo Shell with
mongo
# Connect to a Database
Next we need to connect to our database to access data, we can do this from the Mongo Shell with
use mongodata
If successful we will see the output
switched to db mongodata
# Insert Data
Next we can try to insert an element with the following
db.comments.insert({"name":"myuser", "comment":"Hell World!"})
Mongo uses BSON (basically JSON with some sprinkles) for data storage
We can also insert data as follows
newstuff = [{"name":"Nabeel Valley","comment":"Hello Nabeel. Weather good today"},{"name":"Kefentse Mathibe","comment":"I'm OK!"}]
db.comments.insert(newstuff)
# View Data
We can view our inserted data with
db.comments.find().pretty()
Which will output the following
{
"_id" : ObjectId("5c1c93222712ad7e454a01a2"),
"username" : "myuser",
"email" : "me@email.com"
}
{ "_id" : ObjectId("5c1c94562712ad7e454a01a3"), "name" : "nabeel" }
{
"_id" : ObjectId("5c1c94562712ad7e454a01a4"),
"email" : "unknown@email.com",
"age" : 7
}
Building the Express App
This can all be found in the server.js
file
The Express app will do a few things:
- Serve the necessary static files for the app
- Get and Insert data into Mongo
- Build and send the Mongo content to the frontend
# Importing the Necessary Libraries
I'm making use of the following libraries to
- Read environmental variables
- Create my server
- Parse JSON body from the create form
require('dotenv').config()
// configure express
const express = require('express')
const app = express()
const port = process.env.PORT || 8080
const bodyParser = require('body-parser')
# Configure the Database
I'm using monk to easily interface with our database
const mongo = require('mongodb')
const mongo = require('mongodb')
const monk = require('monk')
const mongoEndpoint = process.env.MONGO_ENDPOINT || 'mongo:27017/mongodata'
const db = monk(mongoEndpoint)
I've used the default value of mongo:27017
for when the application is run in k8s in order to interface with a mongo instance more easily. If running locally we can set the MONGO_ENDPOINT
in a .env
file in the project root directory as follows
MONGO_ENDPOINT=localhost:27017
# Middleware
Configure express middleware for the following
- Use static files
- Parse JSON and Form data from request
- Make DB accessible to the app
app.use(bodyParser.json())
app.use(bodyParser.urlencoded())
app.use(express.static('public'))
app.use((req, res, next) => {
req.db = db
next()
})
# View Comments
Next I define a /comments
that will retrieve content from the comments
collection, render it with the base.card
and base.content
functions and send that as a response
app.get('/comments', function(req, res) {
let db = req.db
let collection = db.get('comments')
collection.find({}, {}, function(e, docs) {
const base = require('./base')
let content = ''
docs.reverse().forEach(comment => {
content += base.card(comment.name, comment.comment, comment._id)
})
content = base.content(content)
res.send(content)
})
})
# Creeate Comment
To create a comment I've used a simple form in the frontend, which can be seen below
<form action="/submit" method="post">
<div class="form-row">
<div class="col-lg-12 mb-3">
<label for="nameInput">Full Name</label>
<input
type="text"
class="form-control"
id="nameInput"
placeholder="John Doe"
value=""
required
name="name"
/>
</div>
<div class="col-lg-12 mb-3">
<label for="commentInput">Comment</label>
<input
type="text"
class="form-control"
id="commentInput"
placeholder=""
value=""
required
name="comment"
/>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
And an express route to handle the post and insert the new comment to the database
app.post('/submit', (req, res) => {
// Set our internal DB variable
let db = req.db
// Set our collection
let collection = db.get('comments')
// Submit to the DB
collection.insert(req.body, function(err, doc) {
if (err) {
// If it failed, return error
const base = require('./base')
const content = base.content(
'<h1>There was an error sending your content, please try again<h2>'
)
res.send(content)
} else {
// get id of inserted element
console.log(doc._id)
// And forward to success page
res.redirect(`comments`)
// res.redirect(`comments/${doc._id}`)
}
})
})
Deploy on k8s
Once we are done we can push this as a Docker image and deploy it on a Kubernetes Cluster as follows
# Building the Image
From the application directory run
docker build -t <USERNAME>/comments-app
docker push
# Deploying on Kubernetes
Once logged into a kubernetes cluster we can make use of the express.yaml
to deploy the express app, and the mongo.yaml
file to deploy Mongo
kubectl create -f express.yaml
kubectl create -f mongo.yaml
This will create a deployment as well as a service for both the Express App and Mongo. The deployment configs are as follows
express.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
app: comments-app
name: comments-app
spec:
replicas: 1
selector:
matchLabels:
app: comments-app
template:
metadata:
labels:
app: comments-app
name: comments-app
spec:
containers:
- image: nabeelvalley/comments-app
imagePullPolicy: Always
name: comments-app
---
apiVersion: v1
kind: Service
metadata:
labels:
app: comments-app
name: comments-app
spec:
ports:
- name: tcp-8080-8080-comments-app
nodePort: 30016
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: comments-app
type: LoadBalancer
mongo.yaml
apiVersion: v1
kind: Service
metadata:
name: mongo
labels:
run: mongo
spec:
ports:
- port: 27017
targetPort: 27017
protocol: TCP
selector:
run: mongo
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: mongo
spec:
template:
metadata:
labels:
run: mongo
spec:
containers:
- name: mongo
image: mongo
ports:
- containerPort: 27017
Running Locally
If you'd like to run this application on a local Kubernetes cluster, take a look at the page on Deploying an Express App that Uses Mongo on k8s Locally