Returning JSON responses with Flask
October 26, 2020 ‐ 3 min read
My most common use case for Flask is making APIs. And I like my APIs to respond with JSON. Flask comes with a jsonify()
function that returns JSON as a Flask Response object.
The reason to use jsonify()
over a regular json.dumps()
is that jsonify()
sets the Content-Type
HTTP header to application/json
. Whereas the output of json.dumps()
is just plain text.
An example of responding with JSON is shown below. You can pass a dict or a list to the jsonify()
function. This is then transformed to a JSON string.
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/chopstick/')
def chopstick():
chopstick = {
'color': 'bamboo',
'left_handed': True
}
return jsonify(chopstick)
if __name__ == '__main__':
app.run()
The above example returns the following JSON object if we call the /chopstick/
endpoint.
$ curl localhost:5000/chopstick/
{
"color": "bamboo",
"left_handed": true
}
Alternatively you can use keyword arguments as well with jsonify()
. So the following produces the same end result.
@app.route('/chopstick/')
def chopstick():
return jsonify(
color='bamboo',
left_handed=True
)
Adding status codes to a JSON response
This jsonify()
is nice and all, but it doesn't give us the opportunity the set a status code for the response we are returning.
Lets say for example that we want the /chopstick/
endpoint to work with a chopstick id. In case the id isn't found in the URI we want to return a 400 status for a bad request.
So to illustrate, let say the chopstick function is responsible for handling both the /chopstick/
and /chopstick/<id>
routes. If the chopstick_id
is None
, so not present in the URI, we return a 400 status with a appropriate error message.
@app.route('/chopstick/')
@app.route('/chopstick/<int:chopstick_id>')
def chopstick(chopstick_id=None):
if not chopstick_id:
return # status 400 - bad request
return jsonify(
id=chopstick_id,
color='bamboo',
left_handed=True,
)
To do so we can use the make_response()
function in Flask. We still make use of jsonify()
in combination with this make_response()
so that the error message is a correct JSON string.
from flask import Flask, jsonify, make_response
app = Flask(__name__)
@app.route('/chopstick/')
@app.route('/chopstick/<int:chopstick_id>')
def chopstick(chopstick_id=None):
if not chopstick_id:
message = jsonify(message='"chopstick_id" missing')
return make_response(message, 400)
return jsonify(
id=chopstick_id,
color='bamboo',
left_handed=True,
)
if __name__ == '__main__':
app.run()
If we now curl the endpoint without an ID we see the error message with the 400 status code as response.
$ curl -i localhost:5000/chopstick/
HTTP/1.0 400 BAD REQUEST
Content-Type: application/json
Content-Length: 44
Server: Werkzeug/1.0.1 Python/3.8.5
Date: Sun, 25 Oct 2020 09:04:22 GMT
{
"message": "\"chopstick_id\" missing"
}
And ofcourse, the chopstick itself is returned with status 200 if we do specify an ID in the URI.
$ curl -i localhost:5000/chopstick/5
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 60
Server: Werkzeug/1.0.1 Python/3.8.5
Date: Sun, 25 Oct 2020 09:05:57 GMT
{
"color": "bamboo",
"id": 5,
"left_handed": true
}
Flask Version
$ flask --version
Python 3.8.5
Flask 1.1.2
Werkzeug 1.0.1