8

I have the following resource:

class Image(Resource):
    def get(self, db_name, col_name, image_id):
        col = mongo_client[db_name][col_name]
        image = col.find_one({'_id':ObjectId(image_id)})
        try:
            image['_id'] = str(image['_id'])
        except TypeError:
            return {'image': 'notFound'}
        return {'image':image}

linked to a certain endpoint.

However, image contains certain datetime objects inside. I could wrap this around with `json.dumps(..., default=str), but I see that there is a way of enforcing this on flask-restful. It's just not clear to me what exactly needs to be done.

In particular, I read:

    It is possible to configure how the default Flask-RESTful JSON
    representation will format JSON by providing a RESTFUL_JSON
    attribute on the application configuration. 
    This setting is a dictionary with keys that 
     correspond to the keyword arguments of json.dumps().

class MyConfig(object):
    RESTFUL_JSON = {'separators': (', ', ': '),
                    'indent': 2,
                    'cls': MyCustomEncoder}

But it's not clear to me where exactly this needs to be placed. Tried a few things and it didn't work.

EDIT:

I finally solved with this:

Right after

api = Api(app)

I added:

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            #return int(obj.strftime('%s'))
            return str(obj)
        elif isinstance(obj, datetime.date):
            #return int(obj.strftime('%s'))
            return str(obj)
        return json.JSONEncoder.default(self, obj)


def custom_json_output(data, code, headers=None):
    dumped = json.dumps(data, cls=CustomEncoder)
    resp = make_response(dumped, code)
    resp.headers.extend(headers or {})
    return resp

api = Api(app)
api.representations.update({
    'application/json': custom_json_output
})
elelias
  • 4,552
  • 5
  • 30
  • 45
  • Can you not just straight up convert each datetime as `image['date'] = str(image['date'])` – Pav Sidhu Jan 18 '17 at 19:27
  • I could, but then I would have to go through every variable that has the issue, for every function that calls the server, which I don't think is very efficient – elelias Jan 19 '17 at 12:37

2 Answers2

3

Just cleared this out, you just have to do the following:

app = Flask(__name__)
api = Api(app)
app.config['RESTFUL_JSON'] = {'cls':MyCustomEncoder}

This works both for plain Flask and Flask-RESTful.

NOTES:

1) Apparently the following part of the documentation is not that clear:

It is possible to configure how the default Flask-RESTful JSON representation will format JSON by providing a RESTFUL_JSON attribute on the application configuration. This setting is a dictionary with keys that correspond to the keyword arguments of json.dumps().

class MyConfig(object):
    RESTFUL_JSON = {'separators': (', ', ': '),
                    'indent': 2,
                    'cls': MyCustomEncoder}

2)Apart from the 'cls' argument you can actually overwrite any keyword argument of the json.dumps function.

0

Having created a Flask app, e.g. like so:

root_app = Flask(__name__)

place MyConfig in some module e.g. config.py and then configure root_app like:

root_app.config.from_object('config.MyConfig')
rtkaleta
  • 681
  • 6
  • 14
  • that seemed to work in the sense that the configuration file was picked, but the serialisation error still persists, I used `str` in place of `MyCustomEncoder` – elelias Jan 19 '17 at 12:36
  • Well, your question was mostly about how to ensure the app respects your custom config, so I'd appreciate the approval. Edit your answer to include the stack trace and we can think about the serialisation bug itself too :) – rtkaleta Jan 19 '17 at 13:14
  • you are right, I managed to make it work following a different approach, but thanks. – elelias Jan 19 '17 at 13:38
  • Thanks! For the benefit of others -> how did you solve the serialisation problem? – rtkaleta Jan 19 '17 at 15:26