Skip to content

Commit

Permalink
Merge pull request #52 from edx/alangsto/customize_basepath
Browse files Browse the repository at this point in the history
  • Loading branch information
alangsto authored Sep 24, 2020
2 parents faa9b8e + ffdc8ec commit 5447d6b
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 8 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ Change Log
Unreleased
----------

1.3.2 --- 2020-09-23
____________________

* Adding option to specify url patterns for generated docs.

1.3.1 --- 2020-05-29
--------------------

Expand Down
28 changes: 28 additions & 0 deletions docs/excluding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,31 @@ For example::
"""
Nor will this.
"""

Additionally, api-docs can be generated only for specified URL patterns. This also
allows documentation for endpoints outside of the ``/api/`` path.

The following code will result in generated documentation only for the ``/test/hedgehog/v1/info`` endpoint::

urlpatterns = []

urlpatterns += [
url(r'/api/hedgehog/v1/info', HedgehogInfoView.as_view()),
url(r'/api/hedgehog/v1/undoc-view', HedgehogUndocumentedView.as_view()),
url(r'/test/hedgehog/v1/info', HedgehogInfoView.as_view()),
url(r'/test/hedgehog/v1/undoc-view', HedgehogUndocumentedView.as_view()),
]

display_urls = [
url(r'/test/hedgehog/v1/info', HedgehogInfoView.as_view()),
]

urlpatterns += make_docs_urls(
make_api_info(
title="edX Hedgehog Service API",
version="v1",
email="hedgehog-support@example.com",
description="A REST API for interacting with the edX hedgehog service.",
),
api_url_patterns=display_urls,
)
2 changes: 1 addition & 1 deletion edx_api_doc_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@
)


__version__ = '1.3.1'
__version__ = '1.3.2'

default_app_config = 'edx_api_doc_tools.apps.EdxApiDocToolsConfig'
42 changes: 35 additions & 7 deletions edx_api_doc_tools/conf_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
from rest_framework import permissions


def make_docs_urls(api_info):
def make_docs_urls(api_info, api_url_patterns=None):
"""
Create API doc views given an API info object.
Arguments:
api_info (openapi.Info): Information about the API.
api_url_patterns (list of url patterns): URL patterns that API docs will be generated for
Returns: list[RegexURLPattern]
A list of url patterns to the API docs.
Expand All @@ -32,8 +33,8 @@ def make_docs_urls(api_info):
urlpatterns += make_docs_urls(api_info)
"""
return get_docs_urls(
docs_data_view=make_docs_data_view(api_info),
docs_ui_view=make_docs_ui_view(api_info),
docs_data_view=make_docs_data_view(api_info, api_url_patterns),
docs_ui_view=make_docs_ui_view(api_info, api_url_patterns),
)


Expand Down Expand Up @@ -103,12 +104,13 @@ def get_docs_urls(docs_data_view, docs_ui_view):
]


def make_docs_data_view(api_info):
def make_docs_data_view(api_info, api_url_patterns=None):
"""
Build View for API documentation data (either JSON or YAML).
Arguments:
api_info (openapi.Info): Information about the API.
api_url_patterns (list of url patterns): URL patterns that API docs will be generated for
Returns: View
Expand All @@ -118,20 +120,24 @@ def make_docs_data_view(api_info):
api_info = make_api_info(title="Awesome API", version="v42")
my_data_view = make_docs_data_view(api_info)
"""
schema_generator = get_schema_generator(api_url_patterns)

return get_schema_view(
api_info,
generator_class=ApiSchemaGenerator,
generator_class=schema_generator,
public=True,
permission_classes=(permissions.AllowAny,),
patterns=api_url_patterns,
).without_ui(cache_timeout=get_docs_cache_timeout())


def make_docs_ui_view(api_info):
def make_docs_ui_view(api_info, api_url_patterns=None):
"""
Build View for browsable API documentation.
Arguments:
api_info (openapi.Info): Information about the API.
api_url_patterns (list of url patterns): URL patterns that API docs will be generated for
Returns: View
Expand All @@ -141,11 +147,14 @@ def make_docs_ui_view(api_info):
api_info = make_api_info(title="Awesome API", version="v42")
my_ui_view = make_docs_ui_view(api_info)
"""
schema_generator = get_schema_generator(api_url_patterns)

return get_schema_view(
api_info,
generator_class=ApiSchemaGenerator,
generator_class=schema_generator,
public=True,
permission_classes=(permissions.AllowAny,),
patterns=api_url_patterns,
).with_ui('swagger', cache_timeout=get_docs_cache_timeout())


Expand All @@ -171,6 +180,25 @@ def determine_path_prefix(self, paths):
return "/api/"


def get_schema_generator(patterns):
"""
Get correct schema generator.
Defaults to ApiSchemaGenerator if no url patterns are specified, meaning
that base path will be "/api".
Arguments:
patterns (list of url patterns): URL patterns that API docs will be generated for
Returns:
Schema generator object.
"""
if patterns:
return OpenAPISchemaGenerator
else:
return ApiSchemaGenerator


def get_docs_cache_timeout():
"""
Return OPENAPI_CACHE_TIMEOUT setting, or zero if it's not defined.
Expand Down
33 changes: 33 additions & 0 deletions example/urls_with_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
REST API URLs for testing make_docs_urls with url pattern specified.
"""

from django.conf.urls import url

from edx_api_doc_tools import make_api_info, make_docs_urls

from .views import HedgehogInfoView, HedgehogUndocumentedView


urlpatterns = []

urlpatterns += [
url(r'/api/hedgehog/v1/info', HedgehogInfoView.as_view()),
url(r'/api/hedgehog/v1/undoc-view', HedgehogUndocumentedView.as_view()),
url(r'/test/hedgehog/v1/info', HedgehogInfoView.as_view()),
url(r'/test/hedgehog/v1/undoc-view', HedgehogUndocumentedView.as_view()),
]

display_urls = [
url(r'/test/hedgehog/v1/info', HedgehogInfoView.as_view()),
]

urlpatterns += make_docs_urls(
make_api_info(
title="edX Hedgehog Service API",
version="v1",
email="hedgehog-support@example.com",
description="A REST API for interacting with the edX hedgehog service.",
),
api_url_patterns=display_urls,
)
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
actual_schema.json
actual_schema_with_patterns.json
66 changes: 66 additions & 0 deletions tests/expected_schema_with_patterns.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"basePath": "/test/hedgehog/v1",
"consumes": [
"application/json"
],
"definitions": {},
"host": "testserver",
"info": {
"contact": {
"email": "hedgehog-support@example.com"
},
"description": "A REST API for interacting with the edX hedgehog service.",
"title": "edX Hedgehog Service API",
"version": "v1"
},
"paths": {
"/info": {
"get": {
"description": "Returns a object with keys and values describing the API.\n\nArgs:\n request: a Request.",
"operationId": "info_list",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"summary": "Get information about the Hedgehog API.",
"tags": [
"info"
]
},
"parameters": [],
"put": {
"description": "This is to show the difference in treatment. This is a second\nparagraph which will be included in the docs.",
"operationId": "info_update",
"parameters": [],
"responses": {
"200": {
"description": ""
}
},
"summary": "Not really an endpoint at all, but has no @schema decorator.",
"tags": [
"info"
]
}
}
},
"produces": [
"application/json"
],
"schemes": [
"http"
],
"security": [
{
"Basic": []
}
],
"securityDefinitions": {
"Basic": {
"type": "basic"
}
},
"swagger": "2.0"
}
30 changes: 30 additions & 0 deletions tests/test_doc_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from edx_api_doc_tools.apps import EdxApiDocToolsConfig
from edx_api_doc_tools.internal_utils import split_docstring
from example import urls as example_urls
from example import urls_with_pattern as test_pattern_urls


@override_settings(ROOT_URLCONF=example_urls.__name__)
Expand Down Expand Up @@ -152,3 +153,32 @@ def mock_app_ready(self, *args, **kwargs):
with pytest.raises(ImproperlyConfigured, match="drf_yasg\' must also be added"):
self.original_app_ready_fn(*args, **kwargs)
self.called_app_ready = True


@override_settings(ROOT_URLCONF=test_pattern_urls.__name__)
class DocViewPatternTests(SimpleTestCase):
"""
Test that the API docs generated from the example Hedgehog API look right.
"""
maxDiff = None # Always show full diff output.

base_path = os.path.dirname(__file__)
path_of_expected_schema = os.path.join(base_path, 'expected_schema_with_patterns.json')
path_of_actual_schema = os.path.join(base_path, 'actual_schema_with_patterns.json')

def test_get_data_view(self):
"""
Same test as above, but with different urls and expected_schema
"""
response = self.client.get('/swagger.json')
assert response.status_code == 200
actual_schema = response.json()
with open(self.path_of_actual_schema, 'w') as f:
json.dump(actual_schema, f, indent=4, sort_keys=True)
with open(self.path_of_expected_schema, 'r') as schema_file:
expected_schema = json.load(schema_file)
assert actual_schema == expected_schema, (
"Generated schema (dumped to {}) "
"did not match schema loaded from expected_schema_with_patterns.json."
.format(os.path.relpath(self.path_of_actual_schema))
)

0 comments on commit 5447d6b

Please sign in to comment.