Skip to main content

JSON & Data Serialization

To customize how data is serialized to and from JSON in this project, you can use the JSONProvider system for general application data or the TaggedJSONSerializer for session-specific data.

Customizing Application JSON Behavior

You can customize JSON serialization by subclassing DefaultJSONProvider and assigning it to app.json. This allows you to handle custom Python types or modify the underlying json.dumps and json.loads behavior.

from flask import Flask
from flask.json.provider import DefaultJSONProvider

class MyCustomType:
def __init__(self, value):
self.value = value

class CustomJSONProvider(DefaultJSONProvider):
def default(self, o):
if isinstance(o, MyCustomType):
return {"_type": "MyCustomType", "value": o.value}
return super().default(o)

def loads(self, s, **kwargs):
# Example of adding an object_hook to loads
def object_hook(obj):
if obj.get("_type") == "MyCustomType":
return MyCustomType(obj["value"])
return obj

kwargs.setdefault("object_hook", object_hook)
return super().loads(s, **kwargs)

app = Flask(__name__)
app.json = CustomJSONProvider(app)

The DefaultJSONProvider already includes support for several common types:

  • datetime.datetime and datetime.date (serialized to RFC 822 strings via werkzeug.http.http_date)
  • uuid.UUID (serialized to strings)
  • dataclasses.dataclass (serialized via dataclasses.asdict)
  • markupsafe.Markup (serialized via its __html__ method)

Using jsonify for Responses

The jsonify function uses the application's configured JSONProvider to create a response with the application/json mimetype.

from flask import jsonify

@app.route("/data")
def get_data():
# Supports positional arguments for lists
return jsonify(1, 2, 3)
# Or keyword arguments for dicts
# return jsonify(id=1, name="Flask")

Tagged Serialization for Complex Types

For scenarios like session management where you need to preserve Python types across serialization (lossless serialization), use the TaggedJSONSerializer. This serializer uses "tags" to mark types that are not standard JSON.

To add support for a custom type in the session, create a subclass of JSONTag and register it with the session interface's serializer.

from flask import Flask
from flask.json.tag import JSONTag, TaggedJSONSerializer

class User:
def __init__(self, name):
self.name = name

class TagUser(JSONTag):
key = " u" # Unique tag key

def check(self, value):
return isinstance(value, User)

def to_json(self, value):
# Convert Python object to a JSON-serializable format
return self.serializer.tag(value.name)

def to_python(self, value):
# Convert JSON-serializable format back to Python object
return User(value)

app = Flask(__name__)
# Register the tag with the session serializer
app.session_interface.serializer.register(TagUser)

The TaggedJSONSerializer includes default tags for:

  • dict (tagged as di if it contains a key that looks like a tag)
  • tuple (tagged as t)
  • bytes (tagged as b and base64 encoded)
  • Markup (tagged as m)
  • UUID (tagged as u)
  • datetime (tagged as d)

Global JSON Functions

The flask.json module provides dumps, dump, loads, and load functions that automatically use the current application's JSONProvider if an application context is active.

from flask import json

# Uses app.json.dumps if inside an app context
data = {"key": "value"}
json_string = json.dumps(data)

# Uses app.json.loads if inside an app context
original_data = json.loads(json_string)

Troubleshooting and Configuration

  • App Context Requirement: Functions in flask.json (like dumps and loads) and jsonify require an active application context to use the custom app.json provider. If no context is active, they fall back to the default Python json module behavior.
  • Sorting and ASCII: You can control global JSON behavior via DefaultJSONProvider attributes or app configuration:
    • DefaultJSONProvider.sort_keys (defaults to True): Controls whether keys are sorted alphabetically.
    • DefaultJSONProvider.ensure_ascii (defaults to True): Controls whether non-ASCII characters are escaped.
  • Registration Order: When using TaggedJSONSerializer.register, the index parameter is important if one tag's check method might return true for a value that another tag should handle (e.g., a subclass). Use index=0 to prioritize a specific tag.
  • Removed Parameter: The app parameter was removed from flask.json.dumps and flask.json.loads in version 2.3. These functions now rely entirely on current_app.