Exposing MongoDB Documents with a REST API via Nodejs and Expressjs (Part 3/3)

The internet is full of arguments about whether or not to store images (and blobs generally) in mongodb. I’m of the view it is NOT a bad thing. Especially in the context of Heroku and mLabs.  

This example will build off the previous post (‘Nodejs & Expressjs to Upload and save Image Files into MongoDB’) and uses in the same example site.

A few key points to consider about the general approach.

  1. Hosting user-uploaded files on disk is not a viable solution in Heroku’s hosted nodejs environment. If you really want to do this, you’ll have to introduce Amazon AWS S3 into the mix. Not difficult – just more code than I want to have to format in WordPress (which incidentally, is STILL horrible). 
  2. Passing or sharing mongodb documents from your server-side nodejs to your browser-side app is not a great idea. Particularly for image files. You are foregoing the sophisticated caching capabilities of your browser and proxy servers; both intended to speed up network transit and response times.

The solution is to build a REST API interface in nodejs to access documents (specifically image files) in your mongodb.  This is a well established and simple approach but only if you can avoid getting tangled up in encoding.

The key take away is to note that you want to save your image base64 encoded and NOT the nodejs default of UTF-8.

We’ll start with an Express route to access (.findOne()) our image using the unique mongodb ObjectId (_id) and will use this as the parameter passed in on the REST URL.

Minor changes allow you to use any other unique identifier such as a username or image filename.

You can append this code into the same  /routes/index.js used in the previous example.


router.get('/picture/:picture', function(req, res){
   // assign the URL parameter to a variable
var filename = req.params.picture;
// open the mongodb connection with the connection
// string stored in the variable called url.
   MongoClient.connect(url, function(err, db){
   db.collection('yourcollectionname')
// perform a mongodb search and return only one result.
// convert the variabvle called filename into a valid
// objectId.
     .findOne({'_id': ObjectId(filename)}, function(err, results){
         // set the http response header so the browser knows this
// is an 'image/jpeg' or 'image/png'
res.setHeader('content-type', results.contentType);
// send only the base64 string stored in the img object
// buffer element
         res.send(results.img.buffer);
      });
   });
});

To test this, log into your Heroku dashboard and navigate into your mLabs add-on. Within your Collection you hopefully have some documents uploaded from the earlier post. It should look something like this,


{
"_id": {
    "$oid": "58f8bd6a343aff254131cb17"
    },
"description": "Foo!",
"contentType": "image/jpeg",
"size": 1239201,
"img": "<Binary Data>"
}

Select and copy an ObjectId ($oid). In this example, 58f8bd6a343aff254131cb17

In the browser goto, 

   http://localhost:3000/picture/58f8bd6a343aff254131cb17

Hopefully, you’ll see your jpeg image rendered in the browser.

It will have come out of your mongodb Collection at mLabs, passed through your nodejs route at Heroku, traversed the Clourflare CDN and arrived safely at your browser for rendering and caching.

Or at least that’s how it works in the running example.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s