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?
Serving up Content With Express
It’s easy to serve up static files using Express.
Add the following statement to the require
section at the top of index.js:
path = require('path');
Now add the following line just after the app.set
statement:
app.use(express.static(path.join(__dirname, 'public')));
This tells Express to use the middleware express.static
which serves up static files in response to incoming requests.
path.join(__dirname, 'public')
maps the local subfolder public to the base route /
; it uses the Node.js path
module to create a platform-independent subfolder string.
index.js should now look like the following:
//1
var http = require('http'),
express = require('express'),
path = require('path');
//2
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function (req, res) {
res.send('<html><body><h1>Hello World</h1></body></html>');
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
Using the static handler, anything in /public
can now be accessed by name.
To demonstrate this, kill your Node instance by pressing Control+C, then execute the commands below in Terminal:
mkdir public; edit public/hello.html
Add the following code to hello.html:
<html></body>Hello World</body></html>
This creates a new directory public and creates a basic static HTML file.
Restart your Node instance again with the command node index.js
. Point your browser to http://localhost:3000/hello.html
and you’ll see the newly created page as follows:
Advanced Routing
Static pages are all well and good, but the real power of Express is found in dynamic routing. Express uses a regular expression matcher on the route string and allows you to define parameters for the routing.
For example, the route string can contain the following items:
-
static terms —
/files
only matcheshttp://localhost:300/pages
-
parameters prefixed with “:” —
/files/:filename
matches/files/foo
and/files/bar
, but not/files
-
optional parameters suffixed with “?” —
/files/:filename?
matches both “/files/foo
” and “/files
” -
regular expressions —
/^\/people\/(\w+)/
matches/people/jill
and/people/john
To try it out, add the following route after the app.get
statement in index.js:
app.get('/:a?/:b?/:c?', function (req,res) {
res.send(req.params.a + ' ' + req.params.b + ' ' + req.params.c);
});
This creates a new route which takes up to three path levels and displays those path components in the response body. Anything that starts with a :
is mapped to a request parameter of the supplied name.
Restart your Node instance and point your browser to: http://localhost:3000/hi/every/body
. You’ll see the following page:
“hi” is the value of req.params.a
, “every” is assigned to req.params.b
and finally “body” is assigned to req.params.c
.
This route matching is useful when building REST APIs where you can specify dynamic paths to specific items in backend datastores.
In addition to app.get
, Express supports app.post
, app.put
, app.delete
among others.
Error Handling And Templated Web Views
Server errors can be handled in one of two ways. You can pass an exception up the call stack — and likely kill the app by doing so — or you can catch the error and return a valid error code instead.
The HTTP 1.1 protocol defines several error codes in the 4xx and 5xx range. The 400 range errors are for user errors, such as requesting an item that doesn’t exist: a familiar one is the common 404 Not Found error. 500 range errors are meant for server errors such as timeout or programming errors such as a null dereference.
You’ll add a catch-all route to display a 404 page when the requested content can’t be found. Since the route handlers are added in the order they are set with app.use
or app.
verb, a catch-all can be added at the end of the route chain.
Add the following code between the final app.get
and the call to http.createServer
in index.js:
app.use(function (req,res) { //1
res.render('404', {url:req.url}); //2
});
This code causes the 404 page to be loaded if it is there is no previous call to res.send()
.
There are a few points to note in this segment:
-
app.use(callback)
matches all requests. When placed at the end of the list ofapp.use
andapp.
verb statements, this callback becomes a catch-all. - The call to
res.render(view, params)
fills the response body with output rendered from a templating engine. A templating engine takes a template file called a “view” from disk and replaces variables with a set of key-value parameters to produce a new document.
Wait — a “templating engine”? Where does that come from?
Express can use a variety of templating engines to serve up views. To make this example work, you’ll add the popular Jade templating engine to your application.
Jade is a simple language that eschews brackets and uses whitespace instead to determine the ordering and containment of HTML tags. It also allows for variables, conditionals, iteration and branching to dynamically create the HTML document.
Update the list of dependencies in package.json as follows:
{
"dependencies": {
"express": "3.3.4",
"jade": "1.1.5"
}
Head back to Terminal, kill your Node instance, and execute the following command:
npm update
This downloads and installs the jade
package for you.
Add the following code directly beneath the first app.set
line in index.js:
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
The first line above specifies where the view templates live, while the second line sets Jade as the view rendering engine.
Execute the following command in Terminal:
mkdir views; edit views/404.jade
Add the following code to 404.jade:
doctype html
body
h1= 'Could not load page: ' + url
The first two lines of the Jade template create a new HTML document with a body
element. The third line creates an h1
element inside the body
element due to the indent. Spacing is important in Jade! :]
The text of the h1
element is the concatenated value of “Could not load page” and the value of the url
parameter passed in as part of the res.render()
in index.js.
As a quick check, your index.js file should now look like the following:
var http = require('http'),
express = require('express'),
path = require('path');
var app = express();
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views')); //A
app.set('view engine', 'jade'); //B
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function (req, res) {
res.send('<html><body><h1>Hello World</h1></body></html>');
});
app.use(function (req,res) {
res.render('404', {url:req.url});
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
Restart your instance of Node and use your browser to load the URL http://localhost:3000/show/a/404/page
. You’ll see the page below:
You now have enough starter code in index.js to accept incoming requests and provide some basic responses. All that you’re missing is the database persistence to turn this into a useful web application that can be leveraged from a mobile app.