-
-
Notifications
You must be signed in to change notification settings - Fork 16.5k
add JSON provider interface #4692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
:param kwargs: Treat as a dict to serialize. | ||
""" | ||
obj = self._prepare_response_obj(args, kwargs) | ||
return self._app.response_class(self.dumps(obj), mimetype="application/json") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth a cls default_mimetype here to save extensions having to override this method and as matching with responses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed this more here: #1728 (comment)
I'm not sure this should actually be configurable at all. The original issue seemed to be about a specific type of response, not all JSON responses. Maybe if you want your whole API to have a different vendor type, like GitHub does, but even GitHub applies different mimetypes to different parts. APIs complex enough to use vendor types usually have versioning as well, so they still wouldn't apply globally.
I did originally have this as a JSONProvider.mimetype
attribute, but I ended up moving all existing behavior to DefaultProvider
and keeping the base very simple.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
not know how to serialize. It should return a valid JSON type or | ||
raise a ``TypeError``. | ||
""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about adding a dict_to_object hook here as well (for the loads side). Allows something like this,
class MoneyJSONProvider(DefaultJSONProvider):
@staticmethod
def default(object_):
if isinstance(object_, date):
return http_date(object_)
if isinstance(object_, (Decimal, UUID)):
return str(object_)
if is_dataclass(object_):
return asdict(object_)
if hasattr(object_, "__html__"):
return str(object_.__html__())
if isinstance(object_, Money):
return {'amount': object_.amount, 'currency': object_.currency}
raise TypeError(f"Object of type {type(object_).__name__} is not JSON serializable")
@staticmethod
def dict_to_object(dict_):
if 'amount' in dict_ and 'currency' in dict_:
return Money(Decimal(dict_['amount']), dict_['currency'])
else:
return dict_
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left it out for a few reasons. object_hook
is not as consistently supported by different libraries as default
is, and I didn't want to put a perceived requirement for it on all other providers. You usually want to perform validation when deserializing, and that gets very messy trying to cram it all in object_hook
along with proper error collection. Instead, any project should use a serialization library, leaving the provider to only handle the JSON and basic types.
This adds the ability to fully customize the JSON implementation used by a Flask application. Using a different JSON implementation can greatly speed up API applications that need to work with JSON in most requests.
app.json
is an instance ofFlask.json_provider_class
.flask.json.provider.JSONProvider
is the base class that definesdumps
,dump
,loads
,load
, andresponse
methods, of which onlydumps
andloads
need to be implemented. For example, here's a provider for orjson:The methods in
flask.json
call the methods onapp.json
if an app context is active, or fall back to thejson
library.jsonify
callsapp.json.response
. The|tojson
filter usesapp.json.dumps
.Request.json
usesapp.json.loads
andResponse.json
usesapp.json.dumps
; the test client uses these as well.Customizing
json_encoder
orjson_decoder
on an app or blueprint, and theJSONEncoder
andJSONDecoder
classes, are deprecated. This was not an effective way to use other libraries. Customizing per blueprint was requested by an API extension that is no longer maintained and didn't appear to use the feature. It's not clear how it would work with the new provider interface and added overhead to every request. Instead, API frameworks should be using a dedicated object serialization library, then taking advantage of a fast JSON serializer at the application level.The
DefaultJSONProvider
is the existing implementation using the built-injson
library. Theapp.config
keysJSON_AS_ASCII
,JSON_SORT_KEYS
,JSONIFY_MIMETYPE
, andJSONIFY_PRETTYPRINT_REGULAR
are deprecated and have moved to attributes on the default provider. Other providers are not required to support these options.