Skip to content

Commit

Permalink
add "externalDocs" to operation via extend_schema tfranzel#681
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed Mar 18, 2022
1 parent 291eea3 commit 52d534b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 1 deletion.
15 changes: 15 additions & 0 deletions drf_spectacular/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ def get_operation(self, path, path_regex, path_prefix, method, registry: Compone
if summary:
operation['summary'] = summary

external_docs = self._get_external_docs()
if external_docs:
operation['externalDocs'] = external_docs

parameters = self._get_parameters()
if parameters:
operation['parameters'] = parameters
Expand Down Expand Up @@ -259,6 +263,17 @@ def get_summary(self):
""" override this for custom behaviour """
return None

def _get_external_docs(self):
external_docs = self.get_external_docs()
if isinstance(external_docs, str):
return {'url': external_docs}
else:
return external_docs

def get_external_docs(self):
""" override this for custom behaviour """
return None

def get_auth(self):
"""
Obtains authentication classes and permissions from view. If authentication
Expand Down
11 changes: 10 additions & 1 deletion drf_spectacular/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ def extend_schema(
versions: Optional[List[str]] = None,
examples: Optional[List[OpenApiExample]] = None,
extensions: Optional[Dict[str, Any]] = None,
callbacks: Optional[List[OpenApiCallback]] = None
callbacks: Optional[List[OpenApiCallback]] = None,
external_docs: Optional[Union[Dict[str, str], str]] = None,
) -> Callable[[F], F]:
"""
Decorator mainly for the "view" method kind. Partially or completely overrides
Expand Down Expand Up @@ -297,6 +298,9 @@ def extend_schema(
:param examples: attach request/response examples to the operation
:param extensions: specification extensions, e.g. ``x-badges``, ``x-code-samples``, etc.
:param callbacks: associate callbacks with this endpoint
:param external_docs: Link external documentation. Provide a dict with an "url" key and
optionally a "description" key. For convenience, if only a string is given it is
treated as the URL.
:return:
"""
if methods is not None:
Expand Down Expand Up @@ -401,6 +405,11 @@ def get_callbacks(self):
return callbacks
return super().get_callbacks()

def get_external_docs(self):
if external_docs is not None and is_in_scope(self):
return external_docs
return super().get_external_docs()

if inspect.isclass(f):
# either direct decoration of views, or unpacked @api_view from OpenApiViewExtension
if operation_id is not None or operation is not None:
Expand Down
10 changes: 10 additions & 0 deletions tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2842,3 +2842,13 @@ def view_func(request, format=None):

schema = generate_schema('/x/', view_function=view_func)
assert 'security' not in schema['paths']['/x/']['get']


def test_external_docs(no_warnings):
@extend_schema(responses=SimpleSerializer, external_docs="https://example.com")
@api_view(['GET'])
def view_func(request, format=None):
pass # pragma: no cover

schema = generate_schema('/x/', view_function=view_func)
assert schema['paths']['/x/']['get']['externalDocs'] == {'url': 'https://example.com'}

0 comments on commit 52d534b

Please sign in to comment.