diff --git a/swh/web/api/apidoc.py b/swh/web/api/apidoc.py --- a/swh/web/api/apidoc.py +++ b/swh/web/api/apidoc.py @@ -316,6 +316,7 @@ def api_doc( route: str, + category: str, noargs: bool = False, tags: List[str] = [], api_version: str = "1", @@ -351,6 +352,7 @@ doc_desc = doc_data["description"] APIUrls.add_doc_route( route, + category, re.split(r"\.\s", doc_desc)[0], noargs=noargs, api_version=api_version, diff --git a/swh/web/api/apiurls.py b/swh/web/api/apiurls.py --- a/swh/web/api/apiurls.py +++ b/swh/web/api/apiurls.py @@ -35,6 +35,7 @@ def add_doc_route( cls, route: str, + category: str, docstring: str, noargs: bool = False, api_version: str = "1", @@ -49,6 +50,7 @@ route_view_name = "api-%s-%s" % (api_version, route_name) if route not in cls._apidoc_routes: d = { + "category": category, "docstring": docstring, "route": "/api/%s%s" % (api_version, route), "route_view_name": route_view_name, @@ -60,7 +62,7 @@ def api_route( url_pattern: str, - view_name: Optional[str] = None, + view_name: str, methods: List[str] = ["GET", "HEAD", "OPTIONS"], throttle_scope: str = "swh_api", api_version: str = "1", diff --git a/swh/web/api/views/add_forge_now.py b/swh/web/api/views/add_forge_now.py --- a/swh/web/api/views/add_forge_now.py +++ b/swh/web/api/views/add_forge_now.py @@ -107,7 +107,7 @@ "api-1-add-forge-request-create", methods=["POST"], ) -@api_doc("/add-forge/request/create") +@api_doc("/add-forge/request/create", "request archival") @format_docstring() @transaction.atomic def api_add_forge_request_create(request: Union[HttpRequest, Request]) -> HttpResponse: @@ -190,7 +190,7 @@ "api-1-add-forge-request-update", methods=["POST"], ) -@api_doc("/add-forge/request/update", tags=["hidden"]) +@api_doc("/add-forge/request/update", "request archival", tags=["hidden"]) @format_docstring() @transaction.atomic def api_add_forge_request_update( @@ -281,7 +281,7 @@ "api-1-add-forge-request-list", methods=["GET"], ) -@api_doc("/add-forge/request/list") +@api_doc("/add-forge/request/list", "request archival") @format_docstring() def api_add_forge_request_list(request: Request): """ @@ -352,7 +352,7 @@ "api-1-add-forge-request-get", methods=["GET"], ) -@api_doc("/add-forge/request/get") +@api_doc("/add-forge/request/get", "request archival") @format_docstring() def api_add_forge_request_get(request: Request, id: int): """ diff --git a/swh/web/api/views/content.py b/swh/web/api/views/content.py --- a/swh/web/api/views/content.py +++ b/swh/web/api/views/content.py @@ -23,7 +23,7 @@ "api-1-content-filetype", checksum_args=["q"], ) -@api_doc("/content/filetype/") +@api_doc("/content/filetype/", "metadata") @format_docstring() def api_content_filetype(request: Request, q: str): """ @@ -73,7 +73,7 @@ "api-1-content-language", checksum_args=["q"], ) -@api_doc("/content/language/") +@api_doc("/content/language/", "metadata") @format_docstring() def api_content_language(request: Request, q: str): """ @@ -124,7 +124,7 @@ "api-1-content-license", checksum_args=["q"], ) -@api_doc("/content/license/") +@api_doc("/content/license/", "metadata") @format_docstring() def api_content_license(request: Request, q: str): """ @@ -172,7 +172,7 @@ "api-1-content-raw", checksum_args=["q"], ) -@api_doc("/content/raw/") +@api_doc("/content/raw/", "archive") def api_content_raw(request: Request, q: str): """ .. http:get:: /api/1/content/[(hash_type):](hash)/raw/ @@ -218,7 +218,7 @@ @api_route(r"/content/known/search/", "api-1-content-known", methods=["POST"]) @api_route(r"/content/known/(?P(?!search).+)/", "api-1-content-known") -@api_doc("/content/known/", tags=["hidden"]) +@api_doc("/content/known/", "archive", tags=["hidden"]) @format_docstring() def api_check_content_known(request: Request, q: Optional[str] = None): """ @@ -288,7 +288,7 @@ @api_route( r"/content/(?P[0-9a-z_:]*[0-9a-f]+)/", "api-1-content", checksum_args=["q"] ) -@api_doc("/content/") +@api_doc("/content/", "archive") @format_docstring() def api_content_metadata(request: Request, q: str): """ diff --git a/swh/web/api/views/directory.py b/swh/web/api/views/directory.py --- a/swh/web/api/views/directory.py +++ b/swh/web/api/views/directory.py @@ -24,7 +24,7 @@ "api-1-directory", checksum_args=["sha1_git"], ) -@api_doc("/directory/") +@api_doc("/directory/", "archive") @format_docstring() def api_directory(request: Request, sha1_git: str, path: Optional[str] = None): """ diff --git a/swh/web/api/views/graph.py b/swh/web/api/views/graph.py --- a/swh/web/api/views/graph.py +++ b/swh/web/api/views/graph.py @@ -77,7 +77,7 @@ @api_route(r"/graph/", "api-1-graph-doc") -@api_doc("/graph/") +@api_doc("/graph/", "miscellaneous") def api_graph(request: Request) -> None: """ .. http:get:: /api/1/graph/(graph_query)/ diff --git a/swh/web/api/views/identifiers.py b/swh/web/api/views/identifiers.py --- a/swh/web/api/views/identifiers.py +++ b/swh/web/api/views/identifiers.py @@ -17,7 +17,7 @@ @api_route(r"/resolve/(?P.+)/", "api-1-resolve-swhid") -@api_doc("/resolve/") +@api_doc("/resolve/", "archive") @format_docstring() def api_resolve_swhid(request: Request, swhid: str): """ @@ -74,7 +74,7 @@ @api_route(r"/known/", "api-1-known", methods=["POST"]) -@api_doc("/known/") +@api_doc("/known/", "archive") @format_docstring() def api_swhid_known(request: Request): """ diff --git a/swh/web/api/views/metadata.py b/swh/web/api/views/metadata.py --- a/swh/web/api/views/metadata.py +++ b/swh/web/api/views/metadata.py @@ -26,7 +26,7 @@ f"/raw-extrinsic-metadata/swhid/(?P{SWHID_RE})/", "api-1-raw-extrinsic-metadata-swhid", ) -@api_doc("/raw-extrinsic-metadata/swhid/") +@api_doc("/raw-extrinsic-metadata/swhid/", "metadata") @format_docstring() def api_raw_extrinsic_metadata_swhid(request: Request, target: str): """ @@ -223,7 +223,7 @@ f"/raw-extrinsic-metadata/swhid/(?P{SWHID_RE})/authorities/", "api-1-raw-extrinsic-metadata-swhid-authorities", ) -@api_doc("/raw-extrinsic-metadata/swhid/authorities/") +@api_doc("/raw-extrinsic-metadata/swhid/authorities/", "metadata") @format_docstring() def api_raw_extrinsic_metadata_swhid_authorities(request: Request, target: str): """ @@ -290,7 +290,7 @@ "/raw-extrinsic-metadata/origin/(?P.*)/authorities/", "api-1-raw-extrinsic-metadata-origin-authorities", ) -@api_doc("/raw-extrinsic-metadata/origin/authorities/") +@api_doc("/raw-extrinsic-metadata/origin/authorities/", "metadata") @format_docstring() def api_raw_extrinsic_metadata_origin_authorities(request: Request, origin_url: str): """ diff --git a/swh/web/api/views/origin.py b/swh/web/api/views/origin.py --- a/swh/web/api/views/origin.py +++ b/swh/web/api/views/origin.py @@ -62,7 +62,7 @@ @api_route(r"/origins/", "api-1-origins") -@api_doc("/origins/", noargs=True) +@api_doc("/origins/", "archive", noargs=True) @format_docstring(return_origin_array=DOC_RETURN_ORIGIN_ARRAY) def api_origins(request: Request): """ @@ -117,7 +117,7 @@ @api_route(r"/origin/(?P.+)/get/", "api-1-origin") -@api_doc("/origin/") +@api_doc("/origin/", "archive") @format_docstring(return_origin=DOC_RETURN_ORIGIN) def api_origin(request: Request, origin_url: str): """ @@ -174,7 +174,7 @@ "api-1-origin-search", throttle_scope="swh_api_origin_search", ) -@api_doc("/origin/search/") +@api_doc("/origin/search/", "archive") @format_docstring( return_origin_array=DOC_RETURN_ORIGIN_ARRAY, visit_types=_visit_types() ) @@ -256,7 +256,7 @@ @api_route(r"/origin/metadata-search/", "api-1-origin-metadata-search") -@api_doc("/origin/metadata-search/", noargs=True) +@api_doc("/origin/metadata-search/", "metadata", noargs=True) @format_docstring(return_origin_array=DOC_RETURN_ORIGIN_ARRAY) def api_origin_metadata_search(request: Request): """ @@ -300,7 +300,7 @@ @api_route(r"/origin/(?P.+)/visits/", "api-1-origin-visits") -@api_doc("/origin/visits/") +@api_doc("/origin/visits/", "archive") @format_docstring(return_origin_visit_array=DOC_RETURN_ORIGIN_VISIT_ARRAY) def api_origin_visits(request: Request, origin_url: str): """ @@ -392,7 +392,7 @@ "api-1-origin-visit-latest", throttle_scope="swh_api_origin_visit_latest", ) -@api_doc("/origin/visit/latest/") +@api_doc("/origin/visit/latest/", "archive") @format_docstring(return_origin_visit=DOC_RETURN_ORIGIN_VISIT) def api_origin_visit_latest(request: Request, origin_url: str): """ @@ -436,7 +436,7 @@ @api_route( r"/origin/(?P.+)/visit/(?P[0-9]+)/", "api-1-origin-visit" ) -@api_doc("/origin/visit/") +@api_doc("/origin/visit/", "archive") @format_docstring(return_origin_visit=DOC_RETURN_ORIGIN_VISIT) def api_origin_visit(request: Request, visit_id: str, origin_url: str): """ @@ -478,7 +478,7 @@ @api_route( r"/origin/(?P.+)/intrinsic-metadata/", "api-origin-intrinsic-metadata" ) -@api_doc("/origin/intrinsic-metadata/") +@api_doc("/origin/intrinsic-metadata/", "metadata") @format_docstring() def api_origin_intrinsic_metadata(request: Request, origin_url: str): """ diff --git a/swh/web/api/views/origin_save.py b/swh/web/api/views/origin_save.py --- a/swh/web/api/views/origin_save.py +++ b/swh/web/api/views/origin_save.py @@ -40,7 +40,7 @@ throttle_scope="swh_save_origin", never_cache=True, ) -@api_doc("/origin/save/") +@api_doc("/origin/save/", "request archival") @format_docstring(visit_types=_savable_visit_types()) def api_save_origin(request: Request, visit_type: str, origin_url: str): """ diff --git a/swh/web/api/views/ping.py b/swh/web/api/views/ping.py --- a/swh/web/api/views/ping.py +++ b/swh/web/api/views/ping.py @@ -10,7 +10,7 @@ @api_route(r"/ping/", "api-1-ping") -@api_doc("/ping/", noargs=True) +@api_doc("/ping/", "miscellaneous", noargs=True) def ping(request: Request): """ .. http:get:: /api/1/ping/ diff --git a/swh/web/api/views/raw.py b/swh/web/api/views/raw.py --- a/swh/web/api/views/raw.py +++ b/swh/web/api/views/raw.py @@ -32,7 +32,7 @@ "api-1-raw-object", throttle_scope="swh_raw_object", ) -@api_doc("/raw/") +@api_doc("/raw/", "archive") @format_docstring() def api_raw_object(request: Request, swhid: str): """ diff --git a/swh/web/api/views/release.py b/swh/web/api/views/release.py --- a/swh/web/api/views/release.py +++ b/swh/web/api/views/release.py @@ -15,7 +15,7 @@ @api_route( r"/release/(?P[0-9a-f]+)/", "api-1-release", checksum_args=["sha1_git"] ) -@api_doc("/release/") +@api_doc("/release/", "archive") @format_docstring() def api_release(request: Request, sha1_git: str): """ diff --git a/swh/web/api/views/revision.py b/swh/web/api/views/revision.py --- a/swh/web/api/views/revision.py +++ b/swh/web/api/views/revision.py @@ -42,7 +42,7 @@ @api_route( r"/revision/(?P[0-9a-f]+)/", "api-1-revision", checksum_args=["sha1_git"] ) -@api_doc("/revision/") +@api_doc("/revision/", "archive") @format_docstring(return_revision=DOC_RETURN_REVISION) def api_revision(request: Request, sha1_git: str): """ @@ -85,7 +85,7 @@ "api-1-revision-raw-message", checksum_args=["sha1_git"], ) -@api_doc("/revision/raw/", tags=["hidden"]) +@api_doc("/revision/raw/", "archive", tags=["hidden"]) def api_revision_raw_message(request: Request, sha1_git: str): """Return the raw data of the message of revision identified by sha1_git""" raw = archive.lookup_revision_message(sha1_git) @@ -104,7 +104,7 @@ "api-1-revision-directory", checksum_args=["sha1_git"], ) -@api_doc("/revision/directory/") +@api_doc("/revision/directory/", "archive") @format_docstring() def api_revision_directory( request: Request, sha1_git: str, dir_path: Optional[str] = None @@ -162,7 +162,7 @@ "api-1-revision-log", checksum_args=["sha1_git"], ) -@api_doc("/revision/log/") +@api_doc("/revision/log/", "archive") @format_docstring(return_revision_array=DOC_RETURN_REVISION_ARRAY) def api_revision_log(request: Request, sha1_git: str): """ diff --git a/swh/web/api/views/snapshot.py b/swh/web/api/views/snapshot.py --- a/swh/web/api/views/snapshot.py +++ b/swh/web/api/views/snapshot.py @@ -19,7 +19,7 @@ "api-1-snapshot", checksum_args=["snapshot_id"], ) -@api_doc("/snapshot/") +@api_doc("/snapshot/", "archive") @format_docstring() def api_snapshot(request: Request, snapshot_id: str): """ diff --git a/swh/web/api/views/stat.py b/swh/web/api/views/stat.py --- a/swh/web/api/views/stat.py +++ b/swh/web/api/views/stat.py @@ -11,7 +11,7 @@ @api_route(r"/stat/counters/", "api-1-stat-counters") -@api_doc("/stat/counters/", noargs=True) +@api_doc("/stat/counters/", "miscellaneous", noargs=True) @format_docstring() def api_stats(request: Request): """ diff --git a/swh/web/api/views/utils.py b/swh/web/api/views/utils.py --- a/swh/web/api/views/utils.py +++ b/swh/web/api/views/utils.py @@ -83,9 +83,18 @@ @api_route(r"/", "api-1-endpoints") def api_endpoints(request): """Display the list of opened api endpoints.""" - routes = APIUrls.get_app_endpoints().copy() - for route, doc in routes.items(): + routes_by_category = {} + for route, doc in APIUrls.get_app_endpoints().items(): doc["doc_intro"] = doc["docstring"].split("\n\n")[0] - # Return a list of routes with consistent ordering - env = {"doc_routes": sorted(routes.items())} + routes_by_category.setdefault(doc["category"], []).append(doc) + + for routes in routes_by_category.values(): + routes.sort(key=lambda route: route["route"]) + + # sort routes by alphabetical category name, with 'miscellaneous' at the end + misc_routes = routes_by_category.pop("miscellaneous") + sorted_routes = sorted(routes_by_category.items()) + sorted_routes.append(("miscellaneous", misc_routes)) + + env = {"doc_routes": sorted_routes} return Response(env, template_name="api/endpoints.html") diff --git a/swh/web/api/views/vault.py b/swh/web/api/views/vault.py --- a/swh/web/api/views/vault.py +++ b/swh/web/api/views/vault.py @@ -73,7 +73,7 @@ throttle_scope="swh_vault_cooking", never_cache=True, ) -@api_doc("/vault/flat/") +@api_doc("/vault/flat/", "batch download") @format_docstring() def api_vault_cook_flat(request: Request, swhid: str): """ @@ -148,7 +148,7 @@ throttle_scope="swh_vault_cooking", never_cache=True, ) -@api_doc("/vault/directory/", tags=["deprecated"]) +@api_doc("/vault/directory/", "batch download", tags=["deprecated"]) @format_docstring() def api_vault_cook_directory(request: Request, dir_id: str): """ @@ -174,7 +174,7 @@ f"/vault/flat/(?P{SWHID_RE})/raw/", "api-1-vault-fetch-flat", ) -@api_doc("/vault/flat/raw/") +@api_doc("/vault/flat/raw/", "batch download") def api_vault_fetch_flat(request: Request, swhid: str): """ .. http:get:: /api/1/vault/flat/(swhid)/raw/ @@ -213,7 +213,7 @@ "api-1-vault-fetch-directory", checksum_args=["dir_id"], ) -@api_doc("/vault/directory/raw/", tags=["hidden", "deprecated"]) +@api_doc("/vault/directory/raw/", "batch download", tags=["hidden", "deprecated"]) def api_vault_fetch_directory(request: Request, dir_id: str): """ .. http:get:: /api/1/vault/directory/(dir_id)/raw/ @@ -240,7 +240,7 @@ throttle_scope="swh_vault_cooking", never_cache=True, ) -@api_doc("/vault/gitfast/") +@api_doc("/vault/gitfast/", "batch download") @format_docstring() def api_vault_cook_gitfast(request: Request, swhid: str): """ @@ -315,7 +315,7 @@ throttle_scope="swh_vault_cooking", never_cache=True, ) -@api_doc("/vault/revision/gitfast/", tags=["deprecated"]) +@api_doc("/vault/revision/gitfast/", "batch download", tags=["deprecated"]) @format_docstring() def api_vault_cook_revision_gitfast(request: Request, rev_id: str): """ @@ -341,7 +341,7 @@ f"/vault/gitfast/(?P{SWHID_RE})/raw/", "api-1-vault-fetch-gitfast", ) -@api_doc("/vault/gitfast/raw/") +@api_doc("/vault/gitfast/raw/", "batch download") def api_vault_fetch_revision_gitfast(request: Request, swhid: str): """ .. http:get:: /api/1/vault/gitfast/(swhid)/raw/ @@ -380,7 +380,7 @@ "api-1-vault-fetch-revision_gitfast", checksum_args=["rev_id"], ) -@api_doc("/vault/revision_gitfast/raw/", tags=["hidden", "deprecated"]) +@api_doc("/vault/revision_gitfast/raw/", "batch download", tags=["hidden", "deprecated"]) def _api_vault_revision_gitfast_raw(request: Request, rev_id: str): """ .. http:get:: /api/1/vault/revision/(rev_id)/gitfast/raw/ @@ -404,7 +404,7 @@ throttle_scope="swh_vault_cooking", never_cache=True, ) -@api_doc("/vault/git-bare/") +@api_doc("/vault/git-bare/", "batch download") @format_docstring() def api_vault_cook_git_bare(request: Request, swhid: str): """ @@ -479,7 +479,7 @@ f"/vault/git-bare/(?P{SWHID_RE})/raw/", "api-1-vault-fetch-git-bare", ) -@api_doc("/vault/git-bare/raw/") +@api_doc("/vault/git-bare/raw/", "batch download") def api_vault_fetch_revision_git_bare(request: Request, swhid: str): """ .. http:get:: /api/1/vault/git-bare/(swhid)/raw/ diff --git a/swh/web/templates/api/endpoints.html b/swh/web/templates/api/endpoints.html --- a/swh/web/templates/api/endpoints.html +++ b/swh/web/templates/api/endpoints.html @@ -36,7 +36,9 @@

-
+{% for category, routes in doc_routes %} +

{{ category }}

+ @@ -44,14 +46,14 @@ - {% for route, doc in doc_routes %} + {% for doc in routes %} {% if "upcoming" in doc.tags %} - {% else %} -
Description
+ {% url doc.route_view_name %} + {{ doc.route }} @@ -67,17 +69,10 @@ {% endfor %}
-
+{% endfor %} {% endblock %} diff --git a/swh/web/tests/api/test_apidoc.py b/swh/web/tests/api/test_apidoc.py --- a/swh/web/tests/api/test_apidoc.py +++ b/swh/web/tests/api/test_apidoc.py @@ -81,13 +81,13 @@ def test_apidoc_nodoc_failure(): with pytest.raises(Exception): - @api_doc("/my/nodoc/url/") + @api_doc("/my/nodoc/url/", "test") def apidoc_nodoc_tester(request, arga=0, argb=0): return Response(arga + argb) @api_route(r"/some/(?P[0-9]+)/(?P[0-9]+)/", "api-1-some-doc-route") -@api_doc("/some/doc/route/") +@api_doc("/some/doc/route/", "test") def apidoc_route(request, myarg, myotherarg, akw=0): """ Sample doc @@ -108,7 +108,7 @@ @api_route(r"/test/error/(?P.+)/", "api-1-test-error") -@api_doc("/test/error/") +@api_doc("/test/error/", "test") def apidoc_test_error_route(request, exc_name): """ Sample doc @@ -128,7 +128,7 @@ r"/some/full/(?P[0-9]+)/(?P[0-9]+)/", "api-1-some-complete-doc-route", ) -@api_doc("/some/complete/doc/route/") +@api_doc("/some/complete/doc/route/", "test") def apidoc_full_stack(request, myarg, myotherarg, akw=0): """ Sample doc @@ -151,7 +151,7 @@ @api_route(r"/test/post/only/", "api-1-test-post-only", methods=["POST"]) -@api_doc("/test/post/only/") +@api_doc("/test/post/only/", "test") def apidoc_test_post_only(request, exc_name): """ Sample doc @@ -343,7 +343,7 @@ @api_route(r"/post/endpoint/", "api-1-post-endpoint", methods=["POST"]) -@api_doc("/post/endpoint/") +@api_doc("/post/endpoint/", "test") def apidoc_test_post_endpoint(request): """ .. http:post:: /api/1/post/endpoint/ @@ -433,7 +433,7 @@ @api_route(r"/endpoint/links/in/doc/", "api-1-endpoint-links-in-doc") -@api_doc("/endpoint/links/in/doc/") +@api_doc("/endpoint/links/in/doc/", "test") def apidoc_test_endpoint_with_links_in_doc(request): """ .. http:get:: /api/1/post/endpoint/