Using MongoDB with Flask-RESTful

I’m currently coding a project which its main stones are Flask and MongoDB. However, when I started using Flask-RESTful I’ve ran into some issues. I was returning just the PyMongo cursor expecting that some black magic would happen that would translate the results to JSON automatically (as BSON is basically a JSON on steroids) but this didn’t happen.

If I returned a cursor, the PyMongo cursor object was not serializable. This exception was raised:

TypeError: pymongo.cursor.Cursor object at 0x109bda150 is not JSON serializable

If I returned a single row, the ObjectID inside the row, was also not serializable.

TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable

Inside the bson module we have the json_util, which deals with this. But when using it and returning its already-json converted data, this lead to Flask-RESTful returning escaped quotes because it tried to convert again to JSON.

After some research, I came up with this solution.

The Api object suppports `representations` which are translators of contents (data to xml, json, yaml, whatever…), so what I needed was to set Flask-RESTful to use my own output function, and of course, that function would know how to properly translate MongoDB objects to JSON. The documentation talks about inheriting the Api class and setting a representations dictionary, but for some reason this didn’t work for me, not sure why. Anyway, after looking at Flask-RESTful code, I figured out another way.

After instantiating your own API, you can just reassign the representations variable to something you created.

DEFAULT_REPRESENTATIONS = {'application/json': output_json}
 
rest = Api(app)
rest.representations = DEFAULT_REPRESENTATIONS

And what about the output_json ? There it goes. Quite simple, indeed.

from flask import make_response
 
from bson.json_util import dumps
 
def output_json(obj, code, headers=None):
    """
    This is needed because we need to use a custom JSON converter
    that knows how to translate MongoDB types to JSON.
    """
    resp = make_response(dumps(obj), code)
    resp.headers.extend(headers or {})
 
    return resp

Note we use the custom json dumps from the bson package, this json converter knows how to handle MongoDB stuff.

Use Facebook to Comment on this Post