Changeset View
Changeset View
Standalone View
Standalone View
swh/web/api/apidoc.py
# Copyright (C) 2015-2020 The Software Heritage developers | # Copyright (C) 2015-2020 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU Affero General Public License version 3, or any later version | # License: GNU Affero General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
from collections import defaultdict | from collections import defaultdict | ||||
import functools | import functools | ||||
from functools import wraps | from functools import wraps | ||||
import os | import os | ||||
import re | import re | ||||
import textwrap | import textwrap | ||||
from typing import List | from typing import List | ||||
import docutils.nodes | import docutils.nodes | ||||
import docutils.parsers.rst | import docutils.parsers.rst | ||||
import docutils.utils | import docutils.utils | ||||
import sentry_sdk | |||||
from rest_framework.decorators import api_view | from rest_framework.decorators import api_view | ||||
from swh.web.api.apiresponse import error_response, make_api_response | from swh.web.api.apiresponse import make_api_response | ||||
from swh.web.api.apiurls import APIUrls | from swh.web.api.apiurls import APIUrls | ||||
from swh.web.common.utils import parse_rst | from swh.web.common.utils import parse_rst | ||||
class _HTTPDomainDocVisitor(docutils.nodes.NodeVisitor): | class _HTTPDomainDocVisitor(docutils.nodes.NodeVisitor): | ||||
""" | """ | ||||
docutils visitor for walking on a parsed rst document containing sphinx | docutils visitor for walking on a parsed rst document containing sphinx | ||||
httpdomain roles. Its purpose is to extract relevant info regarding swh | httpdomain roles. Its purpose is to extract relevant info regarding swh | ||||
▲ Show 20 Lines • Show All 252 Lines • ▼ Show 20 Lines | |||||
class APIDocException(Exception): | class APIDocException(Exception): | ||||
""" | """ | ||||
Custom exception to signal errors in the use of the APIDoc decorators | Custom exception to signal errors in the use of the APIDoc decorators | ||||
""" | """ | ||||
def api_doc( | def api_doc( | ||||
route: str, | route: str, noargs: bool = False, tags: List[str] = [], api_version: str = "1", | ||||
noargs: bool = False, | |||||
tags: List[str] = [], | |||||
handle_response: bool = False, | |||||
api_version: str = "1", | |||||
): | ): | ||||
""" | """ | ||||
Decorator for an API endpoint implementation used to generate a dedicated | Decorator for an API endpoint implementation used to generate a dedicated | ||||
view displaying its HTML documentation. | view displaying its HTML documentation. | ||||
The documentation will be generated from the endpoint docstring based on | The documentation will be generated from the endpoint docstring based on | ||||
sphinxcontrib-httpdomain format. | sphinxcontrib-httpdomain format. | ||||
Args: | Args: | ||||
route: documentation page's route | route: documentation page's route | ||||
noargs: set to True if the route has no arguments, and its | noargs: set to True if the route has no arguments, and its | ||||
result should be displayed anytime its documentation | result should be displayed anytime its documentation | ||||
is requested. Default to False | is requested. Default to False | ||||
tags: Further information on api endpoints. Two values are | tags: Further information on api endpoints. Two values are | ||||
possibly expected: | possibly expected: | ||||
* hidden: remove the entry points from the listing | * hidden: remove the entry points from the listing | ||||
* upcoming: display the entry point but it is not followable | * upcoming: display the entry point but it is not followable | ||||
handle_response: indicate if the decorated function takes | |||||
care of creating the HTTP response or delegates that task to the | |||||
apiresponse module | |||||
api_version: api version string | api_version: api version string | ||||
""" | """ | ||||
tags_set = set(tags) | tags_set = set(tags) | ||||
# @api_doc() Decorator call | # @api_doc() Decorator call | ||||
def decorator(f): | def decorator(f): | ||||
# if the route is not hidden, add it to the index | # if the route is not hidden, add it to the index | ||||
Show All 21 Lines | def decorator(f): | ||||
view_name = "api-%s-%s" % (api_version, route_name) | view_name = "api-%s-%s" % (api_version, route_name) | ||||
APIUrls.add_url_pattern(urlpattern, doc_view, view_name) | APIUrls.add_url_pattern(urlpattern, doc_view, view_name) | ||||
@wraps(f) | @wraps(f) | ||||
def documented_view(request, **kwargs): | def documented_view(request, **kwargs): | ||||
doc_data = get_doc_data(f, route, noargs) | doc_data = get_doc_data(f, route, noargs) | ||||
try: | try: | ||||
response = f(request, **kwargs) | return {"data": f(request, **kwargs), "doc_data": doc_data} | ||||
except Exception as exc: | except Exception as exc: | ||||
sentry_sdk.capture_exception(exc) | exc.doc_data = doc_data | ||||
return error_response(request, exc, doc_data) | raise exc | ||||
if handle_response: | |||||
return response | |||||
else: | |||||
return make_api_response(request, response, doc_data) | |||||
return documented_view | return documented_view | ||||
return decorator | return decorator | ||||
@functools.lru_cache(maxsize=32) | @functools.lru_cache(maxsize=32) | ||||
def get_doc_data(f, route, noargs): | def get_doc_data(f, route, noargs): | ||||
▲ Show 20 Lines • Show All 84 Lines • Show Last 20 Lines |