drf-yasg
drf-yasg copied to clipboard
Recursively convert Serializer objects wherever Schema objects are required
I don't understand why I need to pass a serializer to a response variable.
response = {201: MYSERIALIZER}
In my own case, I want to pass data that are not in the serializer. I can't pass dict or str to the response, I keep getting error.
How can I set my custom params or dict in the 'response' variable?
I don't quite understand. The response of an operation must be an OpenAPI response object with or without a Schema object describing its structure. To achieve this you can either use the openapi.Response
helper object, pass a serializer to convert into a schema, pass an openapi.Schema
object, or pass a string to generate a response without a body.
All of this is documented under swagger_auto_schema
.
Checked it.. didn't get that part. I want my response to be
api_response = {'token':'hdhdhd', 'name':'myname'}
response = {200, api_response}
I just want to be able to pass my own dict to the response
variable. Hope you get my point?
I don't, really. You don't put a response dictionary into an API schema specification, you describe the structure of that dictionary. You might be looking to set the examples
field of the Response object or the example
field of the Schema object.
@bobozar
In our project we didn't want to create serializer-per-response either, so we've created a decorator on top of @swagger_auto_schema
decorator, with usage like
class SomeAPIView(APIView):
@schema(
responses={
status.HTTP_200_OK: {
'fields': serializers.ListField(child=serializers.DictField())
}
})
def get(self, request: Request) -> Response:
And code to convert this thing into serializer is:
def make_serializer(fields: dict, name=None) -> Type[BaseSerializer]:
# unique name to avoid setting ref_name setting
cls_name = name or str(int(time.time())) + uuid.uuid4().hex + 'AnonymousSerializer'
bases = (BaseSerializer,)
for name, field in fields.items():
if isinstance(field, type):
raise ValueError(f'Please, instantiate serializer for {name} for docs to work')
return type(cls_name, bases, fields)
# start of the snippet inside decorator
_responses = responses
for status_code, response_body_serializer in (_responses or {}).copy().items():
if isinstance(response_body_serializer, dict):
serializer_cls = make_serializer(fields=response_body_serializer)
_responses[status_code] = serializer_cls
# end of the snippet inside decorator
Code probably won't work as is, there's some other stuff going on in BaseSerializer
and in the decorator, but you get the idea.
@axnsan12, what do you thing about adding this kind of functionality to the library?
I don't see the point. You could just generate an openapi.Schema object instead of a serializer.
Yes, I understand. But we also validate outcoming response bodies against specified serializers, to make sure docs for responses is correct.
And you also can nest serializers inside those dictionaries
responses={
status.HTTP_200_OK: {'dashboard': DashboardModelSerializer()}
}
I don't think I can mix openapi.Schema
objects and serializers, can I?
UPD. Though we're using python3.6, dictionaries are ordered here, I don't need to worry about messed up order of the fields inside the docs. For <3.6 it could be a problem, so, I'm not really sure.
Then I suppose this could be solved by recursively converting Serializer
objects to Schema
objects wherever a Schema
is expected?