Flask jsonify a list of objects

flask, json, python, serialization

Solution

Give your `EqltByGene` an extra method that returns a dictionary:

class EqltByGene(object):
    #

    def serialize(self):
        return {
            'gene_id': self.gene_id, 
            'gene_symbol': self.gene_symbol,
            'p_value': self.p_value,
        }

then use a list comprehension to turn your list of objects into a list of serializable values:

jsonify(eqtls=[e.serialize() for e in my_list_of_eqtls])

The alternative would be to write a hook function for the `json.dumps()` function, but since your structure is rather simple, the list comprehension and custom method approach is simpler.

You can also be really adventurous and subclass `flask.json.JSONEncoder`; give it a `default()` method that turns your `EqltByGene()` instances into a serializable value:

from flask.json import JSONEncoder

class MyJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, EqltByGene):
            return {
                'gene_id': obj.gene_id, 
                'gene_symbol': obj.gene_symbol,
                'p_value': obj.p_value,
            }
        return super(MyJSONEncoder, self).default(obj)

and assign this to the `app.json_encoder` attribute:

app = Flask(__name__)
app.json_encoder = MyJSONEncoder

and just pass in your list directly to `jsonify()`:

return jsonify(my_list_of_eqtls)

You could also look at the Marshmallow project for a more full-fledged and flexible project for serializing and de-serializing objects to Python primitives that easily fit JSON and other such formats; e.g.:

from marshmallow import Schema, fields

class EqltByGeneSchema(Schema):
    gene_id = fields.Integer()
    gene_symbol = fields.String()
    p_value = fields.Float()

and then use

jsonify(eqlts=EqltByGeneSchema().dump(my_list_of_eqtls, many=True)

to produce JSON output. The same schema can be used to validate incoming JSON data and (with the appropriate extra methods), used to produce `EqltByGene` instances again.

Problem

I have a list of objects that I need to jsonify. I've looked at the flask jsonify docs, but I'm just not getting it. My class has several inst-vars, each of which is a string: `gene_id`, `gene_symbol`, `p_value`. What do I need to do to make this serializable as JSON? My naive code: ``` jsonify(eqtls = my_list_of_eqtls) ``` Results in: ``` TypeError: <__main__.EqtlByGene object at 0x1073ff790> is not JSON serializable ``` Presumably I have to tell jsonify how to serialize an `EqtlByGene`, but I can't find an example that shows how to serialize an instance of a class. I've been trying to follow some of the suggestions show below to create my own JSONEncoder subclass. My code is now: ``` class EqtlByGene(Resource): def __init__(self, gene_id, gene_symbol, p_value): self.gene_id = gene_id self.gene_symbol = gene_symbol self.p_value = p_value class EqtlJSONEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, EqtlByGene): return { 'gene_id' : obj.gene_id, 'gene_symbol' : obj.gene_symbol, 'p_value' : obj.p_value } return super(EqtlJSONEncoder, self).default(obj) class EqtlByGeneList(Resource): def get(self): eqtl1 = EqtlByGene(1, 'EGFR', 0.1) eqtl2 = EqtlByGene(2, 'PTEN', 0.2) eqtls = [eqtl1, eqtl2] return jsonify(eqtls_by_gene = eqtls) api.add_resource(EqtlByGeneList, '/eqtl/eqtlsbygene') app.json_encoder(EqtlJSONEncoder) if __name__ == '__main__': app.run(debug=True) ``` When I try to reach it via curl, I get: ``` TypeError(repr(o) + " is not JSON serializable") ```

Original source