-
Notifications
You must be signed in to change notification settings - Fork 1
Home
sampleNodeProject is a basic CRUD app built with node, mongodb, and express.
Today we wrote the server, created a mongo database on mlab.com, wrote two REST Apis, and began working on the front-end javascript and css.
To begin your project, make sure you have node installed on your machine (https://nodejs.org/en/download/). Open a terminal and cd into the directory you want your project to be in.
In the terminal run npm init. This will generate a package.json file, which all node applications need. You can read more about it here https://docs.npmjs.com/cli/init.
We wrote a basic node server that listens on port 8081. We used express to set up the base route. To install express for your project, run npm install express. See http://expressjs.com/en/starter/installing.html.
When a GET request is sent to the base route, our server responds with hello world. Later, we will change it to respond with an array of the items in our collection.
// Here we're creating a basic express application - see http://expressjs.com/en/api.html#express
const express = require('express');
const app = express();
// Check to see if we've set an environment variable for port, otherwise use 8081
const port = process.env.PORT || 8081;
// If we receive a GET request at the base route, send back a message - see http://expressjs.com/en/api.html#app.get.method
app.get('/', function (req, res) {
res.send('hello world');
});
// listen on the port we specified - see http://expressjs.com/en/api.html#app.listen
app.listen(port);
// Just a message to let us know the express application is running
// The console here will be the terminal where you run `npm start`, because this is the server code
console.log('Listening on localhost:', port);
Install mongodb on your project with npm install mongodb.
You can connect to a local database by putting mongodb://localhost:27017/demo in the url variable in index.js. This would require you to run mongod on your machine. We opted to create a mongo database on https://mlab.com/ so that we can access the same data from different machines, and didn't have to set up a local mongod instance.
We added some code that just tests the connection to the database we created.
// This creates a variable called MongoClient - see https://www.npmjs.com/package/mongodb#connect-to-mongodb
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
//Replace `user`, `password`, `instance`, and `port` with your mlab database info.
const url = 'mongodb://<user>:<password>@<instance>.mlab.com:<port>/demo';
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
db.close();
});
We wrote an /add endpoint that will call our addPerson function when it receives a POST request with an object in the body. In order to read req.body as a json object, we had to add the body-parser dependency: npm install body-parser.
const bodyParser = require('body-parser');
// Documentation on app.use - http://expressjs.com/en/4x/api.html#app.use
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
function addPerson(person) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
// Mongo uses 'collection's instead of tables
// Documentation for insertOne: https://docs.mongodb.com/manual/reference/method/db.collection.insertOne/
db.collection('demo').insertOne(person);
db.close();
});
}
app.post('/add', function(req, res) {
let person = req.body;
addPerson(person);
res.send('Added!');
});
We tested the endpoint on Postman to make sure it works the way we expect it to.

Now that we had some items in our database, we wrote a /read endpoint that accepts GET requests and calls our getAllPeople function and responds with an array of all the items in our collection.
app.get('/read', function (req, res) {
getAllPeople(function(people) {
res.send(people);
});
});
function getAllPeople(callback) {
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
db.collection('demo').find({}).toArray(function(err, docs){
callback(docs);
});
db.close();
});
}
TODO: Notice that we use the same code to open the MongoClient each time. We should separate the duplicated code into a reusable function (this is called DRY "don't repeat yourself").
We created a folder called public and put our index.html, style.css, and script.js inside. Next we needed to get the server to send the html in its response when calling the base route. We swapped out the Hello World line with:
getAllPeople(function(people) {
res.sendFile(path.resolve(__dirname, 'public/index.html'));
});
The above code calls our getAllPeople function and includes a callback function as the parameter.
We reference our css and js in our html file, but those files still need to be mounted on the server, In order to serve static files, we call the express.static middleware function:
app.use(express.static('public'));
Our html head includes a link tag referencing style.css, and the body includes a script tag for our script.js file. We want the css to load as soon as possible, but if the javascript loads before the html finishes loading, it might try to act on DOM elements that don't exist yet, so we have the js at the end. It is ok to put the script in the head as long as you wrap it in a function that listens for the DOM to finish loading:
document.addEventListener('DOMContentLoaded', function () {
//code here
}
We've added an empty ul and a form with some buttons to the html.
The first thing we want to do when someone comes to our page is load the list of items that are in the database.
var xhr = new XMLHttpRequest();
xhr.open("GET", "/read");
xhr.send();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
showPeople(JSON.parse(this.responseText));
}
});
There are many libraries on npm that can be used to send http requests. Here, we are using XMLHttpRequest, which is built in to most browsers. You can read more about it here. The request will go through five states (0 - 4) with the last being the ready state. You can read about the states here. It's good to know what each state's name is at the least.
Once the ready state is 4, we know we've received a response, so we call our showPeople function with the response text as the parameter.
function showPeople(data) {
var ul = document.querySelectorAll('#people')[0],
peopleArr = [];
for (var key in data) peopleArr.push(data[key]);
ul.innerHTML = '';
peopleArr.forEach(function(person) {
var li = document.createElement('li');
li.append(person.name);
ul.append(li);
});
}
This function creates a variable called ul that holds a reference to the first DOM element with an id of 'people'. It also creates an empty array, into which we push all of the objects that are inside the response object that we received. Since the objects are now in an array, we can iterate through them using an array method called forEach. You can see all the available array methods here. It is good to be familiar with all of these methods.
As we iterate through the peopleArr array, we're creating li elements, putting the name from the object in them, and then appending each one to the existing ul element.
Now we're showing our data when the page loads, but the submit button still doesn't do anything. So we added an event listener that fires when the button is clicked.
var submit = document.querySelectorAll('#submit')[0];
submit.addEventListener('click', function() {
var name = document.querySelectorAll('#name')[0],
age = document.querySelectorAll('#age')[0],
addXhr = new XMLHttpRequest(),
data = 'age=' + age.value + '&name=' + name.value;
addXhr.open("POST", "/add", true);
addXhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
addXhr.send(data);
addXhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
xhr.open("GET", "/read");
xhr.send();
showPeople();
}
});
});
Now when the submit button is clicked, a POST request is sent with all the data from the form input fields.
We've started to add some basic styling. It is good to know about specificity, which is a way of calculating which css selectors have higher importance. It is also important to know about CSS selectors, which will let you do things like select only elements that have classes starting with a certain string, or select only odd-numbered elements, etc.