Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/topics/documenting-your-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ Two popular options are [Swagger UI][swagger-ui] and [ReDoc][redoc].
Both require little more than the location of your static schema file or
dynamic `SchemaView` endpoint.

openapi allows you to group endpoints by tags, that's you can configure these tags
on your view by adding `openapi_tags` as property, by default will set ['default'].

```python
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response

class HelloWorldApiView(APIView):
permission_classes = [AllowAny]
openapi_tags = ['example', 'hello-world']

def get(self, request):
return Response(data={'message': 'hello world!'})

```

### A minimal example with Swagger UI

Assuming you've followed the example from the schemas documentation for routing
Expand Down
19 changes: 19 additions & 0 deletions rest_framework/schemas/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def get_operation(self, path, method):

operation['operationId'] = self._get_operation_id(path, method)
operation['description'] = self.get_description(path, method)
operation['tags'] = self._get_tags(path, method)

parameters = []
parameters += self._get_path_parameters(path, method)
Expand Down Expand Up @@ -211,6 +212,24 @@ def _get_pagination_parameters(self, path, method):

return paginator.get_schema_operation_parameters(view)

def _get_tags(self, path, method):
"""
Get tags parameters from view

Default value to return it will be tuple with default tag
In other hand it will try to get it from openapi_tags of view
"""

tags = ['default']

if hasattr(self.view, 'openapi_tags'):
tags = getattr(self.view, 'openapi_tags', tags)

assert type(tags) == list, 'openapi_tags property is not a list'
assert len(tags) > 0, 'openapi_tags property should has almost one tag'

return tags

def _map_choicefield(self, field):
choices = list(OrderedDict.fromkeys(field.choices)) # preserve order and remove duplicates
if all(isinstance(choice, bool) for choice in choices):
Expand Down
42 changes: 42 additions & 0 deletions tests/schemas/test_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def test_path_without_parameters(self):
assert operation == {
'operationId': 'listDocStringExamples',
'description': 'A description of my GET operation.',
'tags': ['default'],
'parameters': [],
'responses': {
'200': {
Expand Down Expand Up @@ -157,6 +158,47 @@ def test_path_with_id_parameter(self):
assert operation == {
'operationId': 'RetrieveDocStringExampleDetail',
'description': 'A description of my GET operation.',
'tags': ['default'],
'parameters': [{
'description': '',
'in': 'path',
'name': 'id',
'required': True,
'schema': {
'type': 'string',
},
}],
'responses': {
'200': {
'description': '',
'content': {
'application/json': {
'schema': {
},
},
},
},
},
}

def test_modify_openapi_tags(self):
path = '/example/{id}/'
method = 'GET'

view = create_view(
views.DocStringExampleDetailWithTagsView,
method,
create_request(path)
)
inspector = AutoSchema()
inspector.view = view

operation = inspector.get_operation(path, method)

assert operation == {
'operationId': 'RetrieveDocStringExampleDetailWithTags',
'description': 'A description of my GET operation.',
'tags': ['DocString'],
'parameters': [{
'description': '',
'in': 'path',
Expand Down
11 changes: 11 additions & 0 deletions tests/schemas/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ def get(self, *args, **kwargs):
pass


class DocStringExampleDetailWithTagsView(APIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
openapi_tags = ['DocString']

def get(self, *args, **kwargs):
"""
A description of my GET operation.
"""
pass


# Generics.
class ExampleSerializer(serializers.Serializer):
date = serializers.DateField()
Expand Down