Drf-yasg: Management command?

Created on 25 Dec 2017  路  5Comments  路  Source: axnsan12/drf-yasg

It would be great to have a management command for generating the Swagger/OpenAPI JSON output so that I could do e.g. ./manage.py generate_swagger swagger.json.

I use the output from drf-yasg as the input to swagger-to-flowtype and this would make that process a little easier.

If you give me a pointer to how I might accomplish it I can take a stab at this myself and send a PR, assuming you're open to having it in drf-yasg. :)

enhancement

Most helpful comment

My guess would be that your get_serializer_class method depends on having some context related to a request - when called via the view the context is set by the request to the schema view endpoint, while the command does not have any request to pass (.get_schema(None, ...))

All 5 comments

Hello,

Yes, this sounds useful and non-intrusive to implement, so I'm not opposed to it in principle.

As to the actual implementation, I can't give you any hints on implementing manage commands, as I never did, but for the part of actually generating the swagger document, I'm thinking along the lines of:

  • create an instance of OpenAPISchemaGenerator

    • you're going to need an Info object and an API URL here, perhaps it would make sense to provide settings for those, something like DEFAULT_INFO and DEFAULT_API_URL?

  • call spec = generator.get_schema(None, True)
  • call OpenAPICodecJson(validators=[]).encode(spec) or OpenAPICodecYaml(validators=[]).encode(spec)
  • write it to the target file

hit a snag; in my project i have an APIView that can have multiple serializer classes (and no default); i get this error:

/Users/beau/.envs/home/lib/python3.6/site-packages/django_filters/rest_framework/backends.py:93: UserWarning: <class 'app.views.access_token.AccountAccessToken'> is not compatible with schema generation
  "{} is not compatible with schema generation".format(view.__class__)
/Users/beau/.envs/home/lib/python3.6/site-packages/django_filters/rest_framework/backends.py:93: UserWarning: <class 'api.views.patient.PatientAddressList'> is not compatible with schema generation
  "{} is not compatible with schema generation".format(view.__class__)
/Users/beau/.envs/home/lib/python3.6/site-packages/django_filters/rest_framework/backends.py:93: UserWarning: <class 'api.views.patient.PatientAddressDetail'> is not compatible with schema generation
  "{} is not compatible with schema generation".format(view.__class__)
/Users/beau/.envs/home/lib/python3.6/site-packages/django_filters/rest_framework/backends.py:93: UserWarning: <class 'api.views.patient.PatientSettingDetail'> is not compatible with schema generation
  "{} is not compatible with schema generation".format(view.__class__)
/Users/beau/.envs/home/lib/python3.6/site-packages/django_filters/rest_framework/backends.py:93: UserWarning: <class 'api.views.patient.PatientCareTeamList'> is not compatible with schema generation
  "{} is not compatible with schema generation".format(view.__class__)
/Users/beau/.envs/home/lib/python3.6/site-packages/django_filters/rest_framework/backends.py:93: UserWarning: <class 'api.views.search.Search'> is not compatible with schema generation
  "{} is not compatible with schema generation".format(view.__class__)
Traceback (most recent call last):
  File "./manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/django/core/management/__init__.py", line 356, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/management/commands/generate_swagger.py", line 36, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/generators.py", line 93, in get_schema
    paths = self.get_paths(endpoints, components, request, public)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/generators.py", line 223, in get_paths
    operations[method.lower()] = self.get_operation(view, path, prefix, method, components, request)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/generators.py", line 256, in get_operation
    return view_inspector.get_operation(operation_keys)
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 32, in get_operation
    responses = self.get_responses()
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 151, in get_responses
    response_serializers = self.get_response_serializers()
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 198, in get_response_serializers
    responses = self.get_default_responses()
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 168, in get_default_responses
    default_schema = self.get_request_serializer() or self.get_view_serializer()
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 78, in get_view_serializer
    return self.view.get_serializer()
  File "/Users/beau/.envs/home/lib/python3.6/site-packages/rest_framework/generics.py", line 112, in get_serializer
    return serializer_class(*args, **kwargs)
TypeError: 'NoneType' object is not callable

however, the get_schema_view view works just fine, with no exception... any idea how to achieve that with the code i have in the PR?

i added a default serializer to that APIView and the management command does work; curious why the view works without one though :)

My guess would be that your get_serializer_class method depends on having some context related to a request - when called via the view the context is set by the request to the schema view endpoint, while the command does not have any request to pass (.get_schema(None, ...))

Was this page helpful?
0 / 5 - 0 ratings