Flask
JSON
Web Development
Python
API

Return JSON response from Flask view

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Returning JSON from a Flask view is the normal pattern for APIs, background dashboards, and frontend endpoints consumed by JavaScript. The important part is not just serializing a dictionary, but returning the right status code, headers, and data shape consistently.

Use jsonify for explicit JSON responses

The most direct Flask pattern is jsonify:

python
1from flask import Flask, jsonify
2
3app = Flask(__name__)
4
5
6@app.get("/health")
7def health():
8    return jsonify(
9        status="ok",
10        service="billing-api",
11    )

jsonify creates a Response object, serializes the data as JSON, and sets the Content-Type header to application/json.

You can return lists as well:

python
1@app.get("/users")
2def users():
3    return jsonify(
4        [
5            {"id": 1, "name": "Ana"},
6            {"id": 2, "name": "Lee"},
7        ]
8    )

This is clearer than calling json.dumps(...) yourself and building the response manually.

Return a status code with the JSON body

Most API views need more than a body. Flask lets you return a tuple of response data and status code:

python
1from flask import request
2
3
4@app.post("/users")
5def create_user():
6    payload = request.get_json()
7
8    if not payload or "name" not in payload:
9        return jsonify(error="name is required"), 400
10
11    user = {"id": 3, "name": payload["name"]}
12    return jsonify(user), 201

That produces valid JSON and an HTTP 201 Created response. The same pattern works for 404, 409, 422, or any other API status you need.

If you also need custom headers, return a three-part tuple:

python
return jsonify(user), 201, {"Location": f"/users/{user['id']}"}

Flask can auto-convert dictionaries, but be deliberate

Modern Flask can automatically convert a plain dictionary return value into JSON:

python
@app.get("/version")
def version():
    return {"version": "1.0.0"}

That works, and for very small endpoints it is fine. I still prefer jsonify when writing an API because it makes the intent explicit and keeps response handling consistent across the codebase.

The difference matters even more when teams mix dictionaries, tuples, custom Response objects, and exception handlers. Being explicit reduces surprises.

Handle non-JSON-native types carefully

Some Python values are not directly JSON serializable, such as datetime, Decimal, or custom objects. For those, convert the data into plain JSON-compatible types before returning it.

python
1from datetime import datetime, timezone
2
3
4@app.get("/build")
5def build_info():
6    return jsonify(
7        built_at=datetime.now(timezone.utc).isoformat(),
8        commit="abc1234",
9    )

If you return ORM models or custom classes directly, Flask will not magically know how to serialize them. Convert them into dictionaries first or use a schema layer such as Marshmallow or Pydantic-backed serializers in larger applications.

Build a consistent API response shape

What matters most in real projects is consistency. Decide early whether error responses should look like:

json
{"error": "name is required"}

or:

json
{"errors": [{"field": "name", "message": "required"}]}

Either is fine. What causes problems is changing the response shape from one endpoint to the next. The Flask code for JSON responses is easy; the contract your clients depend on is the harder part.

Common Pitfalls

The most common mistake is using json.dumps(...) and returning the raw string without the proper JSON response headers. That produces text, not a proper Flask JSON response.

Another frequent issue is forgetting the correct status code. A JSON body that says "error" with an HTTP 200 response is harder for clients to handle correctly.

Serialization of unsupported types is another common problem. Convert datetimes, decimals, and custom objects into plain strings, numbers, lists, and dictionaries before returning them.

Finally, avoid returning wildly inconsistent payload shapes across endpoints. Clients care more about stable contracts than about which Flask helper created the response.

Summary

  • Use jsonify when you want an explicit JSON response in Flask.
  • Return (jsonify(...), status_code) for API endpoints that need proper HTTP semantics.
  • Add headers with a three-part return tuple when necessary.
  • Convert non-JSON-native Python values before serializing them.
  • Keep your response shape consistent across the whole API.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

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

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.