Customizing JSON Behavior
Flask uses a provider-based system for JSON operations, allowing you to customize how data is serialized and deserialized. By default, Flask uses the DefaultJSONProvider, which wraps Python's built-in json library and adds support for common types like datetime, UUID, and dataclasses.
Basic Customization
You can modify the behavior of the default JSON provider by changing attributes on the app.json instance. This is useful for adjusting formatting or sorting without creating a new class.
from flask import Flask
app = Flask(__name__)
# Disable ASCII escaping to support non-ASCII characters in output
app.json.ensure_ascii = False
# Disable key sorting for better performance
app.json.sort_keys = False
# Force compact output even in debug mode
app.json.compact = True
The DefaultJSONProvider supports the following configuration attributes:
ensure_ascii: IfTrue(default), non-ASCII characters are escaped.sort_keys: IfTrue(default), dictionary keys are sorted alphabetically.compact: IfTrue, output has no indentation or extra spaces. IfNone(default), it is compact unless the app is in debug mode.mimetype: The mimetype used byjsonify(default is"application/json").
Supporting Custom Types
To support serializing custom objects, you can override the default method of the provider. This method is called for any object that the standard JSON library cannot handle.
from flask import Flask
from flask.json.provider import DefaultJSONProvider
class MyUser:
def __init__(self, name):
self.name = name
class CustomJSONProvider(DefaultJSONProvider):
@staticmethod
def default(obj):
if isinstance(obj, MyUser):
return {"_type": "User", "name": obj.name}
return super(CustomJSONProvider, CustomJSONProvider).default(obj)
app = Flask(__name__)
app.json = CustomJSONProvider(app)
Note that DefaultJSONProvider.default already handles datetime (as RFC 822 strings), UUID, dataclasses, and objects with an __html__ method.
Using Alternative JSON Libraries
If you need to use a faster library like orjson or ujson, you can implement a custom JSONProvider. You must implement at least the dumps and loads methods.
import orjson
from flask import Flask
from flask.json.provider import JSONProvider
class OrjsonProvider(JSONProvider):
def dumps(self, obj, **kwargs):
# orjson.dumps returns bytes, Flask expects a string
return orjson.dumps(obj, **kwargs).decode()
def loads(self, s, **kwargs):
return orjson.loads(s, **kwargs)
app = Flask(__name__)
app.json = OrjsonProvider(app)
When implementing a custom provider, remember that JSONProvider requires an application instance during initialization to maintain a weak reference to the app.
Customizing JSON Loading
You can also customize how JSON is loaded, for example, by providing an object_hook to the underlying json.loads call. This is done by overriding the loads method in a subclass of DefaultJSONProvider.
from flask import Flask
from flask.json.provider import DefaultJSONProvider
class HookProvider(DefaultJSONProvider):
def object_hook(self, obj):
if "_type" in obj and obj["_type"] == "User":
return MyUser(obj["name"])
return obj
def loads(self, s, **kwargs):
kwargs.setdefault("object_hook", self.object_hook)
return super().loads(s, **kwargs)
app = Flask(__name__)
app.json = HookProvider(app)
Registering the Provider
There are two ways to register a custom JSON provider in Flask:
-
Assigning to
app.json: Create an instance of your provider and assign it to thejsonattribute of an existing Flask app.app.json = CustomProvider(app) -
Setting
json_provider_class: SubclassFlaskand set thejson_provider_classattribute. Flask will automatically instantiate it.class MyFlask(Flask):
json_provider_class = CustomProvider
app = MyFlask(__name__)
Troubleshooting
jsonify Arguments
The jsonify function (and the underlying app.json.response method) accepts either positional arguments or keyword arguments, but not both. Passing both will raise a TypeError.
# Valid: positional args (serialized as a list)
jsonify(1, 2, 3)
# Valid: keyword args (serialized as a dict)
jsonify(id=1, name="Flask")
# Invalid: raises TypeError
jsonify(1, 2, name="Flask")
Trailing Newlines
The DefaultJSONProvider.response method adds a trailing newline to the JSON output. This is a standard practice for many HTTP clients and command-line tools like curl. If you implement a custom response method in a JSONProvider subclass, you should decide whether to maintain this behavior.
Key Sorting Requirements
When app.json.sort_keys is enabled (which is the default), all keys in dictionaries must be strings. The json library does not convert keys to strings before sorting, so including non-string keys will result in a TypeError during serialization.