flask-smorest
flask-smorest copied to clipboard
Dynamic serialization schema
It would be useful to reimplement the ResponseMixin.response
function to accept a static function as the schema argument so that we can build the schema based on the client request, which is needed for JSON:API requests and using marshmallow-jsonapi as a serializer.
Below is an example of a use case:
@bp.route('/')
class Resource(MethodView)
def get_fields(request):
fields = parser.parse(JsonApiRequestSchema, request, location='query')
schema = ResourceSchema(many=true, only=fields)
return schema
@bp.response(200, get_fields)
def get(self):
pass
What should the generated doc look like?
I suppose it is necessary to represent a static schema in the generated document. So the document should appear using the passed Marshmallow schema in the response function. Instead serialization should happen based on same schema but using different arguments. To resolve this problem you could define two arguments in the response function only
and exclude
and evaluate them in the decorator inside response.
The following code is an example to integrate a different serialization logic in your project. It can be useful to use JSON:API spec with OpenAPI doc.
from flask import request
class ResponseMixin:
def response(
self, status_code, schema=None, *, description=None,
example=None, examples=None, headers=None,
only=None, exclude=()
):
# ...
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
if schema:
if only:
schema.only = only(request) if callable(only) else set(only)
if exclude:
schema.exclude = exclude(request) if callable(exclude) else set(exclude)
schema._init_fields()
# ...
This link helps to render what I mean.
After a series of tests and evaluations I think it is more appropriate to use a dedicated serialization_schema to give more flexibility to the code and avoid interacting with the internal logic of the schema.
from flask import request
class ResponseMixin:
def response(
self, status_code, schema=None, *, description=None,
example=None, examples=None, headers=None,
serialization_schema=None
):
# ...
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
if serialization_schema:
schema = serialization_schema(request) if callable(serialization_schema) else serialization_schema
# ...