Hints for adding mongodb to your RESTful Node.js service
In this lab, you will create a comments feature for your application. This feature should provide both GET and POST interfaces to your RESTFUL service.
The HTTP verbs comprise a major portion of the "uniform interface" constraints to a REST service. The primary or most-commonly-used HTTP verbs (or methods, as they are properly called) are POST, GET, PUT, and DELETE. These correspond to create, read, update, and delete (or CRUD) operations, respectively.
You will implement a POST on your "http://yourserver.org/comments" REST service for "create" to write a comment to the database, and GET for "read" to read all of the comments from the database.
The following steps may help you in implementing your node.js service utilizing express and mongodb.
First, create a new express application using:
express comments
cd comments
npm install
Now npm start will begin running your server that is pre set up to handle static files.
Get mongodb working on your hosting service. If you are using the bitnami image, you just need to change the authentication settings for mongodb as shown here:
First stop the mongo daemon
sudo /opt/bitnami/ctlscript.sh stop mongodb
Edit the configuration file to turn off authentication
If you are using an EC2 image other than bitnami, or another hosting service, you should follow these steps.(You dont need to do this if you are on bitnami)
Install mongodb. This process is covered in chapter 12 of the textbook. I suggest that you use version 2.4.8 since this is the version used in the book.
cd /usr/local/src
sudo curl -O http://downloads.mongodb.org/linux/mongodb-linux-x86_64-2.4.8.tgz
sudo tar -zxvf mongodb-linux-x86_64-2.4.8.tgz
cd mongodb-linux-x86_64-2.4.8
sudo cp bin/* /usr/local/bin
sudo mkdir /data
sudo mkdir /data/db
sudo nohup mongod --fork --logpath /var/log/mongodb.log
This will start mongod in the background so you can connect to it anytime you are on the machine. You will have to kill it manually if you want it to stop. It will create database files in the default directory "/data/db".
Bitnami users should pick back up here
Chapter 12 in the text will show you how to configure your database and to set up users. Start on page 216 to see how to control access to your database.
Now install the node modules that will allow you to connect to mongo
sudo npm install -g mongoose
You could also get the package.json file. It will have all of the npm packages needed for all exercises in the book. Then run "npm update" to install all of those packages.
For this lab we will be creating and saving comments, so lets start with creating our index.html inside our "/public" folder.
We would like to send a javascript object to our node.js service that has the following form:
{"Name":"Mickey","Comment":"Hello"}
So, lets build this object in a new jquery index.html file and make sure it is formatted correctly before we call our node service.
Comments!
Next you'll need to create your comments.js file inside the "/javascripts" folder.
$(document).ready(function(){
$("#serialize").click(function(){
var myobj = {Name:$("#Name").val(),Comment:$("#Comment").val()};
jobj = JSON.stringify(myobj);
$("#json").text(jobj);
});
});
When the button is clicked, the callback anonymous function will grab the form values, convert them to a JSON string and write them to the "json" div.
Try your jquery html out on your static web server running on your EC2 instance and make sure the #json div has the correct JSON string.
Now lets build the REST service for POST (create in the "crud" vernacular).
We'll start with making a route for the comment REST service in "routes/index.js". It should currently look something like this:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
So, go ahead and delete the existing route (as it is irrelevant to this project), and then you'll want to create a POST route in its spot. It should look something like this to start:
router.post('/comment', function(req, res, next) {
console.log("POST comment route"); //[1]
res.sendStatus(200);
});
Verify that you see the "POST comment route" log in your ssh window when you access the url through curl:
man curl
-d, --data
(HTTP) Sends the specified data in a POST request to the HTTP
server, in the same way that a browser does when a user has
filled in an HTML form and presses the submit button. This will
cause curl to pass the data to the server using the content-type
application/x-www-form-urlencoded.
You will have to use curl to generate a POST request.
curl --data '{"Name":"Mickey","Comment":"Hello"}' http://localhost:3000/comment
Make sure you see the "POST comment route" message in the window where you are running node.
Now lets see if we can generate that same HTTP POST request through your jquery html. Fortunately, it is really easy to do this with jquery, so add the following to your comments.js inside the function run with the "serialize" button.
var url = "comment";
$.ajax({
url:url,
type: "POST",
data: jobj,
contentType: "application/json; charset=utf-8",
success: function(data,textStatus) {
$("#done").html(textStatus);
}
})
Check to make sure you get to your POST route.
Now we need to interpret this data on the back end node service. Due to using express, which has a middleware called body parser, the data will come in one giant block, and we'll need to pick the pieces out that we need. First, check to make sure the request contains what you want by adding the following line to your POST route (before the sendStatus line):
console.log(req.body); //[2]
Once you've confirmed that it does have the correct data, utilize the following line to create a new Comment:
Finally, now that we know the comment we've made is correct, we can save it to our database. This takes two steps. First, we need to connect to the database using mongoose (which we installed earlier). Add the following to your routes/index.js file.
/* Set up mongoose in order to connect to mongo database */
var mongoose = require('mongoose'); //Adds mongoose as a usable dependency
mongoose.connect('mongodb://localhost/commentDB'); //Connects to a mongo database called "commentDB"
var commentSchema = mongoose.Schema({ //Defines the Schema for this database
Name: String,
Comment: String
});
var Comment = mongoose.model('Comment', commentSchema); //Makes an object from that schema as a model
var db = mongoose.connection; //Saves the connection as a variable to use
db.on('error', console.error.bind(console, 'connection error:')); //Checks for connection errors
db.once('open', function() { //Lets us know when we're connected
console.log('Connected');
});
Now you need to put the data from the browser into the database, by adding this to your post route (make sure you take out the old sendStatus)
var newcomment = new Comment(req.body); //[3]
console.log(newcomment); //[3]
newcomment.save(function(err, post) { //[4]
if (err) return console.error(err);
console.log(post);
res.sendStatus(200);
});
Check to see that mongodb has been updated correctly (This is described in the book starting at page 220 and Figure 12.7).
Since we didnt give mongoose a name for the collection, it pluralized the schema name and we get the collection comments.
At this point you have the POST (create in CRUD) part of your REST service complete. You now need to implement the GET (read in CRUD). First install the route in your routes/index.js file.
/* GET comments from database */
router.get('/comment', function(req, res, next) {
console.log("In the GET route");
});
And make sure you can see this log printed out when you go to http://[yourserverip]/comment
Now you need to connect to mongo and read the database entries, so adjust your route to look as follows:
/* GET comments from database */
router.get('/comment', function(req, res, next) {
console.log("In the GET route?");
Comment.find(function(err,commentList) { //Calls the find() method on your database
if (err) return console.error(err); //If there's an error, print it out
else {
console.log(commentList); //Otherwise console log the comments you found
}
})
});
There are more optional parameters to the find function that you could specify to get a subset of the database.
Now that you have the database collection on the server side, you need to send it back to the browser.
res.json(commentList); //Then send them
You should be able to test your REST service by entering the url http://yourserverip/comments into your browser
Now we want to add the jquery code to access this GET part of our REST service.
$("#getThem").click(function() {
$.getJSON('comment', function(data) {
console.log(data);
var everything = "
";
for(var comment in data) {
com = data[comment];
everything += "
";
$("#comments").html(everything);
})
})
Test to make sure you can insert comments using your REST POST route and get the result back using your REST GET route.
I hope you realize the power of having a javascript object that can be passed directly to your node.js REST service that can be placed directly into the mongo database. You can then directly grab the document object out of the database and pass it back to your javascript front end. We didnt cover queries, but you conduct queries by creating an object that is passed to the query interface of mongo.