How To Write A Simple Node.js/MongoDB Web Service for an iOS App
Learn how to create a simple Node.js and MongoDB web service for an iOS app in this tutorial. By Michael Katz.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Write A Simple Node.js/MongoDB Web Service for an iOS App
50 mins
- A Case for Node+Mongo
- Getting Started
- Running a Node.js Script
- Node Packages
- NPM – Using External Node Modules
- Using Express
- A Short Diversion into HTTP Verbs
- Adding a Package to Your Node Instance
- Serving up Content With Express
- Advanced Routing
- Error Handling And Templated Web Views
- Introducing MongoDB
- Adding MongoDB to Your Project
- Creating a MongoDB Collection Driver
- Using Your Collection Driver
- Working With Data
- Updating and Deleting Data
- Where to Go From Here?
Introducing MongoDB
MongoDB is a database that stores JSON objects. Unlike a SQL database, a NoSQL database like Mongo does not support entity relationships. In addition, there is no pre-defined schema, so entities in the same collection (or “table”, in relational-speak) don’t need to have the same fields or conform to any predefined pattern.
MongoDB also provides a powerful querying language map-reduce along with support for location data. MongoDB is popular for its ability to scale, replicate and shard. Scaling and high-availability features are not covered in this tutorial.
The biggest drawbacks of MongoDB are the lack of relationship support and that it can be a memory hog as it memory-maps the actual database file. These issues can be mitigated by carefully structuring the data; this will be covered in part 2 of this tutorial.
Because of the close relationship between MongoDB documents and JSON, MondoDB is a great choice as a database for both web and mobile apps. MongoDB doesn’t store raw JSON; instead, the documents are in a format called BSON — Binary JSON — that is more efficient for data storage and queries. BSON also has the advantage of supporting more datatypes than JSON, such as dates and C-types.
Adding MongoDB to Your Project
MongoDB is a native application and is accessed through drivers. There are a number of drivers for almost any environment, including Node.js. The MongoDB driver connects to the MongoDB server and issues commands to update or read data.
This means you’ll need a running MongoDB instance listening on an open port. Fortunately, that’s your very next step! :]
Open a new instance of Terminal and execute the following commands:
cd /usr/local/opt/mongodb/; mongod
This starts the MongoDB server daemon.
Now the MongoDB service is up and running on the default port of 27017.
Although the MongoDB driver provides database connectivity, it still has to be wired up to the server to translate incoming HTTP requests into the proper database commands.
Creating a MongoDB Collection Driver
Remember the /:a/:b/:c
route you implemented earlier? What if you could use that pattern instead to look up database entries?
Since MongoDB documents are organized into collections, the route could be something simple like: /:collection/:entity
which lets you access objects based on a simple addressing system in an extremely RESTful fashion!
Kill your Node instance and execute the following commands in Terminal:
edit collectionDriver.js
Add the following code to collectionDriver.js:
var ObjectID = require('mongodb').ObjectID;
This line imports the various required packages; in this case, it’s the ObjectID
function from the MongoDB package.
_id
field of datatype ObjectID that MongoDB uses for optimized lookup and insertion. Since ObjectID is a BSON type and not a JSON type, you’ll have to convert any incoming strings to ObjectIDs if they’re to be used when comparing against an “_id” field.Add the following code to collectionDriver.js just after the line you added above:
CollectionDriver = function(db) {
this.db = db;
};
This function defines the CollectionDriver
constructor method; it stores a MongoDB client instance for later use. In JavaScript, this
is a reference to the current context, just like self
in Objective-C.
Still working in the same file, add the following code below the block you just added:
CollectionDriver.prototype.getCollection = function(collectionName, callback) {
this.db.collection(collectionName, function(error, the_collection) {
if( error ) callback(error);
else callback(null, the_collection);
});
};
This section defines a helper method getCollection
to obtain a Mongo collection by name. You define class methods by adding functions to prototype
.
db.collection(name,callback)
fetches the collection object and returns the collection — or an error — to the callback.
Add the following code to collectionDriver.js, below the block you just added:
CollectionDriver.prototype.findAll = function(collectionName, callback) {
this.getCollection(collectionName, function(error, the_collection) { //A
if( error ) callback(error);
else {
the_collection.find().toArray(function(error, results) { //B
if( error ) callback(error);
else callback(null, results);
});
}
});
};
CollectionDriver.prototype.findAll
gets the collection in line A above, and if there is no error such as an inability to access the MongoDB server, it calls find()
on it in line B above. This returns all of the found objects.
find()
returns a data cursor that can be used to iterate over the matching objects. find()
can also accept a selector object to filter the results. toArray()
organizes all the results in an array and passes it to the callback. This final callback then returns to the caller with either an error or all of the found objects in the array.
Still working in the same file, add the following code below the block you just added:
CollectionDriver.prototype.get = function(collectionName, id, callback) { //A
this.getCollection(collectionName, function(error, the_collection) {
if (error) callback(error);
else {
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$"); //B
if (!checkForHexRegExp.test(id)) callback({error: "invalid id"});
else the_collection.findOne({'_id':ObjectID(id)}, function(error,doc) { //C
if (error) callback(error);
else callback(null, doc);
});
}
});
};
In line A above, CollectionDriver.prototype.get
obtains a single item from a collection by its _id
. Similar to prototype.findAll
method, this call first obtains the collection object then performs a findOne
against the returned object. Since this matches the _id
field, a find()
, or findOne()
in this case, has to match it using the correct datatype.
MongoDB stores _id
fields as BSON type ObjectID
. In line C above, ObjectID()
(C) takes a string and turns it into a BSON ObjectID to match against the collection. However, ObjectID()
is persnickety and requires the appropriate hex string or it will return an error: hence, the regex check up front in line B.
This doesn’t guarantee there is a matching object with that _id
, but it guarantees that ObjectID
will be able to parse the string. The selector {'_id':ObjectID(id)}
matches the _id
field exactly against the supplied id
.
Add the following line to collectionDriver.js below the block you just added:
exports.CollectionDriver = CollectionDriver;
This line declares the exposed, or exported, entities to other applications that list collectionDriver.js as a required module.
Save your changes — you’re done with this file! Now all you need is a way to call this file.