Tools for writing and generating API documentation for Open edX REST APIs.
Contents:
First, add edx-api-doc-tools
to your requirements and install it into your
environment.
Next, add the following to your list of installed apps in Django settings:
INSTALLED_APPS = (
... # your other installed apps
drf_yasg,
edx_api_doc_tools,
)
Then, in urls.py
:
...
from edx_api_doc_tools import make_api_info, make_docs_urls
...
api_info = make_api_info(title="Registrar API", version="v2")
urlpatterns += make_docs_urls(api_info)
Your should now be able to load the Swagger UI in a browser at
https://${your_service}/api-docs. Note that by default, documentation is
only generated for views under the root path /api
. Generation for other
views is possible but requires some extra configuration.
Finally, you can enrich the generated documentation:
...
from edx_api_doc_tools import parameter, schema
...
class MyView(APIView):
@schema(
parameters=[
parameter('min_date', str, 'Filter response by minimum date.'),
],
responses={
403: 'User lacks required permission.'
404: 'Resource does not exist.'
# Note that 2xx response is automatically figured out by drf-yasg,
# with reponse schema coming from the serializer, if declared.
},
)
def get(self, request):
"""
Get the resource.
This docstring will be used in the OpenAPI spec, and *supports Markdown!*
"""
...
Documentation for API endpoints starts in the Python files, using docstrings and decorators.
The decorator you use to document an endpoint depends on whether the endpoint’s method is written in your source file, or is implemented by a base class.
For example, in an APIView, you might write explicit get
and post
methods. These can be documented with schema()
decorators directly on
those methods. In a ModelViewSet, you might inherit the list
method, and
document it with a schema_for()
decorator on the class.
If your endpoint is implemented by an explicit handler method, add the
schema()
decorator to the method. The docstring of the method will be
used as the documentation. The first line is the summary, and the rest of the
docstring is the description. Everything is in Markdown format.
Additional arguments to the schema()
decorator provide details of the
parameters and responses.
For example:
...
from edx_api_doc_tools import parameter, schema
...
class MyView(APIView):
@schema(
parameters=[
parameter('min_date', str, 'Filter response by minimum date.'),
],
responses={
403: 'User lacks required permission.'
404: 'Resource does not exist.'
# Note that 2xx response is automatically figured out by drf-yasg,
# with reponse schema coming from the serializer, if declared.
},
)
def get(self, request):
"""
Get the resource.
This docstring will be used in the OpenAPI spec, and *supports Markdown!*
"""
...
If you are documenting an endpoint implemented in a base class, you use
a schema_for()
decorator on your derived class.
Its first argument is the method name it applies to, and the second argument is
a docstring to use for that method. The rest of the arguments are the same as
for schema()
. You can use as many schema_for()
decorators on a
class as you need:
@schema_for(
"list",
"""
Fetch the list of edX hedgehogs.
Hedgehogs can be filtered by minimum weight (grams or ounces),
their favorite food, whether they graduated college,
or any combination of those criterion.
""",
parameters=[
query_parameter('min-grams', int, "Filter on whether minimum weight (grams)."),
query_parameter('min-ounces', float, "Filter hogs by minimum weight (ounces)."),
],
responses={
404: 'Hedgehog with given key not found.',
},
)
@schema_for(
"retrieve",
"""
Fetch details for a _single_ hedgehog by key.
""",
parameters=[
path_parameter(
'hedgehog_key', str, "Key identifying the hog. Lowercase letters only."
),
],
responses={
404: 'Hedgehog with given key not found.',
},
)
class HedgehogViewSet(ModelViewSet):
...
Once installed, edx-api-doc-tools
will automatically generate browsable
documentation for all API endpoints within the /api/
path.
This may not be what you want.
Analogous to the schema()
and schema_for()
decorators,
there exist the exclude_schema
and exclude_schema_for()
decorators,
both of which prevent the target endpoint from appearing in your API documentation.
The former is useful when your endpoint handler is defined directly in your source file,
whereas the latter is useful when the handler is implemented by a base class.
Furthermore, exclude_schema_for()
can be used on a View or Viewset to
exclude multiple endpoints at once.
If you wish to exclude all endpoints for View or Viewset, decorate it with
exclude_schema_for_all
.
For example:
...
from edx_api_doc_tools import exclude_schema, exclude_schema_for, exclude_schema_for_all
...
class MyViewsetWithSomeDocs(ViewSet):
def retrieve(...):
"""
This will appear in the docs.
"""
@exclude_schema
def update(...):
"""
This will NOT appear in the docs.
"""
@exclude_schema_for_all
class MyViewsetWithNoDocs(ViewSet):
def retrieve(...):
"""
This will NOT appear in the docs.
"""
def update(...):
"""
This will NOT appear in the docs.
"""
# Note that ``ModelAPIView`` comes with pre-implemented handlers for
# GET, POST, PUT, PATCH, and DESTROY.
class MyModelViewWithAllDocs(ModelAPIView):
"""
Will have docs for GET, POST, PUT, PATCH, and DESTROY.
"""
@exclude_schema_for('destroy')
class MyModelViewWithMostDocs(ModelAPIView):
"""
Will have docs for GET, POST, PUT, and PATCH.
"""
@exclude_schema_for('put', 'patch', 'destroy')
class MyModelViewWithSomeDocs(ModelAPIView)
"""
Will have docs for GET and POST.
"""
@exclude_schema_for_all
class MyViewModelViewNoDocs(ModelAPIView)
"""
ModelAPIView has handlers for GET, POST, PUT, PATCH, and DESTROY,
but we will not see any docs for this view.
"""
@exclude_schema_for_all
class MyViewWithMostDocs(APIView)
def get(self, request):
"""
This won't appear in the docs.
"""
def post(self, request):
"""
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,
)
Tools for writing and generating API documentation for Open edX REST APIs.
In this file is the public Python API for REST documentation.
A schema generator for /api/*
.
Only includes endpoints in the /api/*
url tree, and sets the path prefix
appropriately.
Return common prefix for all paths.
Return dict of endpoints to be displayed.
Location of API parameter in request.
Decorate an API-endpoint-handling function to exclude it from the API docs.
Example:
class MyView(APIView):
@schema(...)
def get(...):
pass
@exclude_schema
def post(...):
pass
Decorate a class to exlcude one or more of of its methods from the API docs.
method_names (list[str]) – Names of view methods whose operations will be excluded from the generated API documentation.
Example:
@schema_for('get', ...)
@schema_for('delete', ...)
@exclude_schema_for('put', 'patch')
class MyView(RetrieveUpdateDestroyAPIView):
pass
Decorate a class to exlcude all of its methods from the API docs.
view_class (type) – A type, typically a subclass of View or ViewSet.
Example:
@exclude_schema_for_all
class MyView(RetrieveUpdateDestroyAPIView):
pass
Return OPENAPI_CACHE_TIMEOUT setting, or zero if it’s not defined.
Get some reasonable URL patterns to browsable API docs and API docs data.
If these URL patterns don’t work for your service, feel free to construct your own.
docs_data_view (openapi.Info) – JSON/YAML view for API docs data.
docs_ui_view (openapi.Info) – Nice HTML view for API docs.
A list of url patterns to the API docs.
Example:
# File: urls.py
from edx_api_doc_tools import get_docs_urls
from .views import custom_doc_data_view, custom_doc_ui_view
urlpatterns = [ ... ] # Your URL patterns.
urlpatterns += get_docs_urls(custom_doc_data_view, custom_doc_ui_view)
Return whether this request is serving an OpenAPI schema.
Build an API info object.
Returns: openapi.Info
Build View for API documentation data (either JSON or YAML).
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
Example:
from edx_api_doc_tools import make_api_info, make_docs_data_view
api_info = make_api_info(title="Awesome API", version="v42")
my_data_view = make_docs_data_view(api_info)
Build View for browsable API documentation.
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
Example:
from edx_api_doc_tools import make_api_info, make_docs_ui_view
api_info = make_api_info(title="Awesome API", version="v42")
my_ui_view = make_docs_ui_view(api_info)
Create API doc views given an API info object.
api_info (openapi.Info) – Information about the API.
api_url_patterns (list of url patterns) – URL patterns that API docs will be generated for
A list of url patterns to the API docs.
Example:
# File: urls.py
from edx_api_doc_tools import make_docs_urls, make_api_info
urlpatterns = [ ... ] # Your URL patterns.
api_info = make_api_info(title="Awesome API", version="v42")
urlpatterns += make_docs_urls(api_info)
Define a typed parameter.
Returns: openapi.Parameter
Define a parameter in the endpoint’s path.
Type must still be specified.
Define a parameter in the endpoint’s querystring.
Type must still be specified.
Decorate an API-endpoint-handling function to specify its schema.
The operation summary and description are taken from the function docstring. All description fields should be in Markdown and will be automatically dedented.
body – Optional payload used for POST, PUT, and PATCH requests. Accepts a serializer class.
parameters (list[openapi.Parameter]) – Optional list of parameters to the API endpoint.
responses (dict[int, object]) – Optional map from HTTP statuses to either: * a serializer class corresponding to that status * a string describing when that status occurs * an openapi.Schema object * None, which indicates “don’t include this response”.
summary (str) – One-line summary of operation. If None, we attempt to extract it from the first line of the docstring.
description (str) – Optional multi-line description of operation. If None, we attempt to extract it from the rest of the docstring.
request_body (Serializer) – Optional serializer class corresponding to the body of the request.
Decorate a class to specify a schema for one of its methods.
Useful when the method you are describing is not defined inside of your
class body, but is instead defined somewhere up in the DRF view hierarchy.
(For applying a schema directly to a method, use the schema()
decorator).
DRF method names include: list
, retrieve
, get
, post
,
create
, put
, update
, patch
, partial_update
,
delete
, and destroy
.
method_name (str) – Name of the method to decorate.
docstring (str) – Optional summary and description of the operation,
which takes the same format that schema()
expects of function
docstrings (that is, a summary line, followed by a newline,
followed by one or more lines of description).
**schema_kwargs – kwargs to pass to schema()
.
Define a string parameter.
Location must still be specified.
If you have not already done so, create or activate a virtualenv. Unless otherwise stated, assume all terminal code below is executed within the virtualenv.
Dependencies can be installed via the command below.
$ make requirements
edx-api-doc-tools has an assortment of test cases and code quality checks to catch potential problems during development. To run them all in the version of Python you chose for your virtualenv:
$ make validate
To run just the unit tests:
$ make test
To run just the unit tests and check diff coverage
$ make diff_cover
To run just the code quality checks:
$ make quality
To run the unit tests under every supported Python version and the code quality checks:
$ make test-all
To generate and open an HTML report of how much of the code is covered by test cases:
$ make coverage
Added support for django 3.0, 3.1 and 3.2
Removed Django constraints from base.in
Dropped python3.5 support.
Updated the travis-badge in README.rst to point to travis-ci.com
Adding option to include a body parameter in requests.
Adding option to specify url patterns for generated docs.
Removing caniusepython3 as it is no longer needed since python3 upgrade.
Remove support for Django<2.2 and add support for python 3.8
Added three new decorators for excluding endpoints from API documentation generation:
@exclude_schema
@exclude_schema_for(method_name)
@exclude_all_schemas
Compatibility with Django 2.1 and 2.2.
Added documentation.
First release on PyPI.