How to get POSTed JSON in Flask?
Categories:
How to Get POSTed JSON Data in Flask

Learn the correct and robust methods to parse and access JSON data sent via POST requests in your Flask applications, handling various content types and potential errors.
When building web APIs or handling client-side data submissions, receiving JSON data via POST requests is a common requirement. Flask, a popular Python web framework, provides straightforward ways to access this data. However, understanding the nuances of content types and proper parsing is crucial for building robust applications. This article will guide you through the process, from basic access to handling common pitfalls.
Understanding POSTed JSON Data in Flask
When a client sends a POST request with JSON data, it typically sets the Content-Type header to application/json. Flask's request object provides a convenient way to access this data, but it's important to know how it works under the hood. The request.json attribute is your primary tool for this, but it's not always a magic bullet.
sequenceDiagram
participant Client
participant FlaskApp
Client->>FlaskApp: POST /api/data (Content-Type: application/json)
Note over Client,FlaskApp: JSON data in request body
FlaskApp->>FlaskApp: Access request.json
alt Content-Type is application/json
FlaskApp-->>FlaskApp: Parses JSON body
FlaskApp->>Client: 200 OK (Processed data)
else Content-Type is not application/json
FlaskApp-->>FlaskApp: request.json is None or raises error
FlaskApp->>Client: 400 Bad Request (Invalid Content-Type)
endSequence diagram illustrating how Flask handles POSTed JSON data based on Content-Type.
Accessing JSON Data with request.json
The most common and recommended way to get POSTed JSON data in Flask is by using the request.json attribute. Flask automatically parses the request body as JSON if the Content-Type header is set to application/json. If the content type is incorrect or the JSON is malformed, request.json will be None or raise an error, respectively.
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/data', methods=['POST'])
def receive_json_data():
if request.is_json:
data = request.json
# Process the JSON data
name = data.get('name')
age = data.get('age')
if name and age:
return jsonify({"message": f"Received data for {name} (age: {age})"}), 200
else:
return jsonify({"error": "Missing 'name' or 'age' in JSON data"}), 400
else:
return jsonify({"error": "Request must be JSON"}), 400
if __name__ == '__main__':
app.run(debug=True)
request.is_json to check if the incoming request has a Content-Type header indicating JSON (application/json or similar) before attempting to access request.json. This prevents BadRequest exceptions if the client sends non-JSON data.Handling Non-JSON Content Types or Malformed JSON
While request.json is convenient, it's essential to handle cases where the client sends data with an incorrect Content-Type or sends malformed JSON. If request.is_json is False, request.json will return None. If request.is_json is True but the JSON is malformed, Flask will raise a BadRequest exception. You can catch this exception for more graceful error handling.
from flask import Flask, request, jsonify
from werkzeug.exceptions import BadRequest
app = Flask(__name__)
@app.route('/api/robust_data', methods=['POST'])
def receive_robust_json_data():
try:
if not request.is_json:
return jsonify({"error": "Content-Type must be application/json"}), 400
data = request.json
if data is None:
# This case should ideally be caught by request.is_json or BadRequest
# but serves as an extra safeguard if parsing somehow yields None
return jsonify({"error": "Could not parse JSON data"}), 400
# Example processing
item_name = data.get('item')
quantity = data.get('quantity')
if item_name and quantity is not None:
return jsonify({"message": f"Order received for {quantity} x {item_name}"}), 200
else:
return jsonify({"error": "Missing 'item' or 'quantity'"}), 400
except BadRequest as e:
return jsonify({"error": f"Malformed JSON: {e.description}"}), 400
except Exception as e:
# Catch any other unexpected errors
return jsonify({"error": f"An unexpected error occurred: {str(e)}"}), 500
if __name__ == '__main__':
app.run(debug=True)
request.data and manually decoding it with json.loads() unless you have a specific reason (e.g., handling non-standard JSON content types or very large payloads). request.json is generally safer and more convenient as it handles content type checks and error propagation automatically.Testing Your Flask Endpoint
To test your Flask application, you can use tools like curl or Postman. Here are examples of how to send valid and invalid JSON requests to your endpoints.
Valid JSON Request
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "Alice", "age": 30}' \
http://127.0.0.1:5000/api/data
Expected Output:
{
"message": "Received data for Alice (age: 30)"
}
Missing Field
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "Bob"}' \
http://127.0.0.1:5000/api/data
Expected Output:
{
"error": "Missing 'name' or 'age' in JSON data"
}
Incorrect Content-Type
curl -X POST -H "Content-Type: text/plain" \
-d '{"name": "Charlie", "age": 25}' \
http://127.0.0.1:5000/api/data
Expected Output:
{
"error": "Request must be JSON"
}
Malformed JSON
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "David", "age": 40,' \
http://127.0.0.1:5000/api/robust_data
Expected Output:
{
"error": "Malformed JSON: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand."
}