4

I'm trying to create a simple API using Flask. I now want to return a list of dicts as follows:

print results  # prints out [{'date': '2014-09-25 19:00:00', 'title': u'Some Title'}]
response = make_response(jsonify(results))
response.headers['Content-Type'] = 'application/json'
return response

But when I go the the url in the browser, I get the following:

{
  "date": "title"
}

Does anybody know what I'm doing wrong here? All tips are welcome!

2 Answers 2

8

This is only an issue for Flask versions before 0.11; if you still see this problem the best thing to do is to upgrade to a later version, as 0.10 is quite ancient by now.


For Flask up to version 0.10, jsonify() will only accept dictionaries. If you give it a list, it'll turn the object into a dictionary, with dict(argument). See the Flask.jsonify() documentation:

Creates a Response with the JSON representation of the given arguments with an application/json mimetype. The arguments to this function are the same as to the dict constructor.

(Emphasis mine)

In your case you have a list with one element, and that element, when iterated over, has 2 values. Those two values then become the key and value of the output dictionary:

>>> results = [{'date': '2014-09-25 19:00:00', 'title': u'Some Title'}]
>>> dict(results)
{'date': 'title'}

That's because the dict() constructor either takes another dictionary, keyword arguments or an iterable of (key, value) pairs.

The solution is to not pass in a list, but give it, at the very least, a key:

response = jsonify(results=results)

jsonify() already returns a response object, there is no need to call make_response() on it. The above produces a JSON object with a 'results' key and your list as the value.

jsonify() only takes a dictionary for security reasons. Quoting the documentation again:

For security reasons only objects are supported toplevel. For more information about this, have a look at JSON Security.

If you really want to bypass this, you'll have to create your own response:

from Flask import json

response = make_response(json.dumps(results), mimetype='application/json')
Sign up to request clarification or add additional context in comments.

5 Comments

Ah, that makes sense. But what if I do want to supply a list, and not a dictionary? Isn't it common for APIs to simply return a list of objects?
@kramer65: APIs generally wrap lists of objects in an object for security reasons. I've updated the answer with references and how to work around this if you want to ignore the advice.
@kramer65 import json; json.dumps(results), then make_response on that
This is no longer true as of Flask 0.11
@JeffWidman: yup, so the question doesn't apply to anyone on a recent Flask version. I've updated the answer to reflect this.
1

This should no longer be an issue now that Flask's jsonify() method serializes top-level arrays (as of this commit).

You'll need to be on Flask >= 0.11.

For convenience, you can either pass in a Python list: jsonify([1,2,3]) Or pass in a series of args: jsonify(1,2,3)

Both will be converted to: [1,2,3]

Details here: http://flask.pocoo.org/docs/dev/api/#flask.json.jsonify

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.