Package: drf-openapi3
DRF OpenApi 3OpenApi 3 utility for Django REST FrameworkEnhances DRF AutoSchema and SchemaGenerator to help generating a better OpenApi 3 documentation.Supports servers, deprecated and summary in schema generation,
now you mark them as deprecated and display the summary besides the description.
If you want your ApiView to display custom content in the documentation,
you can add it by writing comments to the view/view method in YAML format.
Fixed request body and responses for views that handle multiple objects,
such as bulk insert, bulk update and bulk delete. Now they are displayed as array.InstallationInstall the package usingpip install drf_openapi3Adddrf_openapi3.apps.OpenApi3Configto DjangoINSTALLED_APPSConfigurationOpenApi documentation ViewExtenddrf_openapi3.views.OpenApiTemplateView. You can define a title and template name, otherwise default values will be used.fromdjango.contrib.auth.mixinsimportLoginRequiredMixinfromdrf_openapi3.viewsimportOpenApiTemplateViewclassMyOpenApiTemplateView(LoginRequiredMixin,OpenApiTemplateView):title='My OpenAPI'template_name='path/to/mytemplate.html'Add schema to urlpatterns usingdrf_openapi3.AdvancedSchemaGeneratoras generator classfromdjango.contrib.auth.decoratorsimportlogin_requiredfromdjango.urlsimportpathfromdrf_openapi3.schemas.advancedimportAdvancedSchemaGeneratorfromrest_framework.schemasimportget_schema_viewurlpatterns=[# Use the `get_schema_view()` helper to add a `SchemaView` to project URLs.#   * `title` and `description` parameters are passed to `SchemaGenerator`.#   * Provide view name for use with `reverse()`.path('my-schema/',login_required(get_schema_view(title='My API',description='My API description',version='1.0.0',generator_class=AdvancedSchemaGenerator,public=True,),login_url='/accounts/login/',),name='my_schema_name'),# ...# ...]Start writing your ApiViews.fromrest_framework.genericsimportListAPIViewclassMyAPIListView(ListAPIView):allowed_methods=['get']defget(self,request,*args,**kwargs):returnsuper(MyAPIListView,self).list(request,*args,**kwargs)How to useLet's see step by step what you can do.Define multiple serversUseful for instance if you provide a test sandbox together with a production server.
In Django settings you can define url and description inAPI_SERVERS:API_SERVERS=[{"url":"https://test.example.com/","description":"Sandbox server (uses test data)",},{"url":"https://example.com/","description":"Production server (uses live data)",},]If you don't define anything, DjangoBASE_URLwill be used to build your server block.
So if you are developing in local environment, the serverurlwill behttp://localhost:8000.
If it's production environment, the serverurlwill behttps://example.com.
Keep in mind that defining multiple servers inAPI_SERVERSwill allow users to switch server urls in the dropdown on the documentation before testing your endpoints.Apply tags to your ApiViewIf you want to tag your view, just passtagsto your view schema. Default is "api".
You can decide your own, it can come in handy to add the endpoint version:fromdrf_openapi3.schemas.advancedimportAdvancedAutoSchemafromrest_framework.genericsimportListAPIViewclassMyAPIListView(ListAPIView):# ...# ...allowed_methods=['get']schema=AdvancedAutoSchema(tags=["v0"],component_name="My",operation_id_base="MyAPI",handles_many_objects=True)defget(self,request,*args,**kwargs):returnsuper(MyAPIListView,self).list(request,*args,**kwargs)Apply deprecated to your old ApiViewIf you want to mark your view as deprecated, just add the attributedeprecated = Trueto your view schema:fromdrf_openapi3.schemas.advancedimportAdvancedAutoSchemafromrest_framework.genericsimportListAPIViewclassMyAPIListView(ListAPIView):# ...# ...allowed_methods=['get']schema=AdvancedAutoSchema(tags=["v0"],component_name="My",operation_id_base="MyAPI",handles_many_objects=True,deprecated=True)defget(self,request,*args,**kwargs):returnsuper(MyAPIListView,self).list(request,*args,**kwargs)Views that handle multiple objects with methods besides GETWhen you write a view that performs bulk create, update or delete operations you face some issues on the documentation:theresponsesfield schema types areobject, but they should bearray.By addinghandles_many_objects=Trueattribute to your view schema, you tell the schema thatresponsesmust be array.fromdrf_openapi3.schemas.advancedimportAdvancedAutoSchemafromrest_framework.genericsimportListCreateAPIViewfromrest_framework.responseimportResponsefromrest_framework.statusimportHTTP_400_BAD_REQUEST,HTTP_200_OKclassMyListPostView(ListCreateAPIView):# ...# ...allowed_methods=['get','post']schema=AdvancedAutoSchema(tags=["v0"],component_name="My",operation_id_base="MyAPI",handles_many_objects=True,)defpost(self,request,*args,**kwargs)->Response:serialized=self.get_serializer(data=request.data,many=True)ifserialized.is_valid():serialized.save()returnResponse(serialized.data,status=HTTP_200_OK)returnResponse(serialized.errors,status=HTTP_400_BAD_REQUEST)Display custom content in the documentationDRF AutoSchema already reads your view/view method Docstring:if you want to display the endpointdescriptionin your documentation,
you can write some text in the view/view method Docstring.That wasn't enough for me though.Let's start with the simplest one, the same one that's already implemented from DRF AutoSchema that it has been kept to have backwards compatibility:we add a plain description in the view Docstring. If we do it on both view and method view, only method view Docstring will be taken into account:fromdrf_openapi3.schemas.advancedimportAdvancedAutoSchemafromrest_framework.genericsimportListCreateAPIViewfromrest_framework.responseimportResponsefromrest_framework.statusimportHTTP_400_BAD_REQUEST,HTTP_200_OKclassMyListPostView(ListCreateAPIView):"""This is my endpoint description and it will be reportedfor each allowed method."""# ...# ...allowed_methods=['get','post']schema=AdvancedAutoSchema(tags=["v0"],component_name="My",operation_id_base="MyListPost",handles_many_objects=True,)defpost(self,request,*args,**kwargs)->Response:"""... and that's my method descriptionSince both the descriptions are defined you'll see only this one.You won't see "This is my endpoint description",unless you delete the text here above."""serialized=self.get_serializer(data=request.data,many=True)ifserialized.is_valid():serialized.save()returnResponse(serialized.data,status=HTTP_200_OK)returnResponse(serialized.errors,status=HTTP_400_BAD_REQUEST)If you want to manage custom changes to your schema, just add them to the Docstring in YAML format.
You'll notice that it'll be easier for you to read your code too.By default DRF AutoSchema displays only status code 200 as example response.
Since 400, 401, 403, 404 status codes return a JSON{"detail": <error detail>},
in Django settings you can defineSTATIC_ERROR_CODES = Trueto display more responses in your documentation.
If you have to perform further changes on responses in your view, you can put them in YAML view/view method Docstring.If you want to limit the allowed response codes that you're going to see on the documentation,
just list the allowed status codes in your view (allowed_status_codes); this is useful when you had enabledSTATIC_ERROR_CODESand you want to prevent some responses to be displayed.We're getting creative here, let's add a complete example:fromdrf_openapi3.schemas.advancedimportAdvancedAutoSchemafromrest_framework.genericsimportListAPIView,CreateAPIView,UpdateAPIView,DestroyAPIViewclassMyCommentedView(ListAPIView,CreateAPIView,UpdateAPIView,DestroyAPIView):"""get:summary: Summary for get methoddescription: Description for get methodpost:summary: Summary for post methoddescription: Description for post method400:description: Invalid object, that's a custom description of 400 response code for post methodput:summary: Summary for put methoddescription: Description for put methoddelete:summary: Summary for delete methoddescription: Description for delete method200:description: Corsa objects deleted, that's a custom description of 200 response code for delete methodschema:type: arrayitems:properties:field:type: booleandescription: Deleted flag, here we define a different schema for bulk delete"""allowed_methods=("GET","POST","PUT","DELETE")allowed_status_codes=(200,400,401,403)schema=AdvancedAutoSchema(tags=["v0"],component_name="MyCommented",operation_id_base="MyCommentedWriteDelete",handles_many_objects=True,)# ...# ...If you've overridden the view methods already (.get(),.post(),.put(),.delete()) you can write there your comments.
Please be advised that if you do so you must not use the notationmethod: properties:fromrest_framework.genericsimportListAPIView,DestroyAPIViewfromrest_framework.responseimportResponsefromrest_framework.statusimportHTTP_200_OKclassMyCommentedView(ListAPIView,DestroyAPIView):defdelete(self,request,*args,**kwargs)->Response:"""summary: Summary for delete methoddescription: Description for delete method200:description: Corsa objects deleted, that's a custom description of 200 response code for delete methodschema:type: arrayitems:properties:field:type: booleandescription: Deleted flag, here we define a different schema for bulk delete"""output=[]fordatainrequest.data:# ...# ...passreturnResponse(output,status=HTTP_200_OK)Last but not least: do you want to set a default sort for your endpoints?
Just passindex=ntoAdvancedAutoSchema:fromdrf_openapi3.schemas.advancedimportAdvancedAutoSchemafromrest_framework.genericsimportListAPIView,ListCreateAPIViewclassMyAPIListView(ListAPIView):# ...# ...allowed_methods=['get']schema=AdvancedAutoSchema(index=0,tags=["v0"],component_name="My",operation_id_base="MyAPI",handles_many_objects=True,deprecated=True)classMyListPostView(ListCreateAPIView):"""This is my endpoint description and it will be reportedfor each allowed method."""# ...# ...allowed_methods=['get','post']schema=AdvancedAutoSchema(index=1,tags=["v0"],component_name="My",operation_id_base="MyListPost",handles_many_objects=True,)