From 46f57580687b1cff6f2ced19c84bdf14624d75b2 Mon Sep 17 00:00:00 2001 From: Yannick de Jong Date: Tue, 4 Aug 2026 15:23:44 +0200 Subject: [PATCH] Fix 404 on versioned API root endpoints --- src/simdb/remote/apis/__init__.py | 36 ++++++++++++++++++------------- tests/remote/api/test_index.py | 16 ++++++++++++++ 2 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 tests/remote/api/test_index.py diff --git a/src/simdb/remote/apis/__init__.py b/src/simdb/remote/apis/__init__.py index b75a9680..2f8a7803 100644 --- a/src/simdb/remote/apis/__init__.py +++ b/src/simdb/remote/apis/__init__.py @@ -36,6 +36,26 @@ def register(api, version, namespaces): version_str = version.replace(".", "_") blueprint = Blueprint(f"api_{version_str}", f"{__name__}.{version_str}") blueprints[version] = blueprint + + def index(): + return jsonify( + { + "api": "simdb", + "api_version": api.version, + "server_version": __version__, + "endpoints": [ + request.url + "simulations", + request.url + "files", + request.url + "validation_schema", + request.url + "metadata", + request.url + "upload_options", + ], + "documentation": request.url + "docs", + } + ) + + api.render_root = index + api.init_app(blueprint) for namespace in namespaces: @@ -78,21 +98,7 @@ def handle_authentication_error(err: Exception): class Index(Resource): @api.doc(security=[]) def get(self): - return jsonify( - { - "api": "simdb", - "api_version": api.version, - "server_version": __version__, - "endpoints": [ - request.url + "simulations", - request.url + "files", - request.url + "validation_schema", - request.url + "metadata", - request.url + "upload_options", - ], - "documentation": request.url + "docs", - } - ) + return index() @api.route("/token") class Token(Resource): diff --git a/tests/remote/api/test_index.py b/tests/remote/api/test_index.py new file mode 100644 index 00000000..608fadcc --- /dev/null +++ b/tests/remote/api/test_index.py @@ -0,0 +1,16 @@ +import pytest + +from simdb.remote.apis import blueprints + + +@pytest.mark.parametrize("version", list(blueprints)) +def test_versioned_index(client, version): + """The versioned root must serve the index JSON, not flask-restx's 404 root.""" + rv = client.get(f"/{version}/") + + assert rv.status_code == 200 + assert rv.json["api"] == "simdb" + # v1 reports "1.0" for blueprint key "v1", so only compare the prefix + assert rv.json["api_version"].startswith(version.lstrip("v")) + assert "server_version" in rv.json + assert any(url.endswith("simulations") for url in rv.json["endpoints"])