Flask
JSON
POST request
Web development
Python

How to get POSTed JSON in Flask?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In Flask, the normal way to read posted JSON is request.get_json(). That gives you parsed JSON from the request body as long as the client sent valid JSON with the right content type. The rest of the work is not parsing but validating the payload shape and returning clear errors when the client sends something malformed.

Use request.get_json() as the Primary API

A basic route that accepts JSON looks like this.

python
1from flask import Flask, jsonify, request
2
3app = Flask(__name__)
4
5@app.post("/users")
6def create_user():
7    data = request.get_json(silent=True)
8    if data is None:
9        return jsonify(error="Expected a valid JSON body"), 400
10
11    return jsonify(received=data), 200
12
13if __name__ == "__main__":
14    app.run(debug=True)

You can test it with curl.

bash
curl -X POST http://127.0.0.1:5000/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Mina","age":31}'

Using silent=True is convenient when you want invalid JSON to produce None instead of raising immediately. That lets your route return a consistent error response under your control.

Check the Content Type Intentionally

If the endpoint is supposed to accept JSON only, it is worth checking the content type before deeper validation.

python
1@app.post("/profiles")
2def create_profile():
3    if not request.is_json:
4        return jsonify(error="Content-Type must be application/json"), 415
5
6    data = request.get_json(silent=True)
7    if data is None:
8        return jsonify(error="Malformed JSON body"), 400
9
10    return jsonify(ok=True, data=data), 200

This makes the API contract clear. A bad content type is a different client error from malformed JSON.

Parsing Is Not Validation

A JSON body can be syntactically valid and still be wrong for your application. After parsing, you should validate required fields, types, and business rules.

python
1@app.post("/profiles")
2def create_profile():
3    if not request.is_json:
4        return jsonify(error="Content-Type must be application/json"), 415
5
6    data = request.get_json(silent=True)
7    if data is None:
8        return jsonify(error="Malformed JSON body"), 400
9
10    name = data.get("name")
11    age = data.get("age")
12
13    errors = []
14    if not isinstance(name, str) or not name.strip():
15        errors.append("name must be a non-empty string")
16    if not isinstance(age, int) or age < 0:
17        errors.append("age must be a non-negative integer")
18
19    if errors:
20        return jsonify(errors=errors), 422
21
22    return jsonify(message="profile created", profile=data), 201

This separation keeps the route logic much easier to reason about:

  • first parse,
  • then validate,
  • then act.

Nested JSON Needs Careful Access

Nested request bodies are common, but direct indexing can turn a client mistake into a server exception.

python
1@app.post("/orders")
2def create_order():
3    data = request.get_json(silent=True)
4    if data is None:
5        return jsonify(error="Malformed JSON body"), 400
6
7    customer = data.get("customer")
8    if not isinstance(customer, dict):
9        return jsonify(error="customer must be an object"), 422
10
11    address = customer.get("address")
12    if not isinstance(address, dict):
13        return jsonify(error="customer.address must be an object"), 422
14
15    city = address.get("city")
16    if not isinstance(city, str) or not city.strip():
17        return jsonify(error="customer.address.city is required"), 422
18
19    return jsonify(message="order accepted", city=city), 201

This is safer than chaining direct dictionary lookups and hoping every nested field exists.

Prefer Flask Parsing Over Manual json.loads(request.data)

You can manually parse the request body yourself, but Flask already gives you a request-aware JSON API. request.get_json() handles the common case more cleanly and makes the intent obvious.

Manual parsing is usually only necessary when you have unusual content-handling rules. For standard JSON API endpoints, the built-in method is the better default.

Common Pitfalls

  • Using request.data and manual JSON parsing when request.get_json() already solves the problem cleanly.
  • Assuming posted JSON is always a dictionary. It can be another valid JSON type.
  • Accepting malformed or non-JSON requests without distinguishing between content-type errors and payload errors.
  • Accessing nested keys directly and turning bad client input into server exceptions.
  • Stopping at parsing and forgetting to validate fields, types, and required structure.

Summary

  • In Flask, use request.get_json() to read posted JSON.
  • Check request.is_json when the endpoint should only accept application/json.
  • Treat parsing and validation as separate steps.
  • Access nested data carefully so client mistakes do not crash the route.
  • Use Flask’s built-in request parsing before reaching for manual json.loads logic.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.