Skip to content

Commit 19d5b4a

Browse files
committed
refactor(api): merge POST route groups under one Swagger tag
- Addresses review feedback on #186 - Gives both POST blueprints a shared tag so the Swagger docs show a single POST group whether or not the store-backed routes are registered - APIFlask emits one top-level tag entry per blueprint, so the shared tag would appear twice in openapi.json (OpenAPI requires unique tag names) - Added a spec processor decorator to depulicate list. - Added supporting test
1 parent 7a0d28a commit 19d5b4a

3 files changed

Lines changed: 28 additions & 2 deletions

File tree

app/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ def create_app(settings: Settings | None = None) -> APIFlask:
4848
app.config["STORAGE_ENABLED"] = settings.storage_enabled
4949
app.config["PROFILES_PATH"] = settings.profiles_path
5050

51+
# APIFlask emits one top-level tag entry per blueprint, so the two POST
52+
# blueprints sharing a tag would duplicate it; OpenAPI requires unique
53+
# tag names.
54+
@app.spec_processor
55+
def dedupe_spec_tags(spec):
56+
seen = set()
57+
spec["tags"] = [
58+
t for t in spec.get("tags", []) if not (t["name"] in seen or seen.add(t["name"]))
59+
]
60+
return spec
61+
5162
# Always available:
5263
app.register_blueprint(health_bp)
5364
app.register_blueprint(v1_post_bp, url_prefix="/v1/ro_crates")

app/ro_crates/routes/post_routes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
)
1111

1212
# Always-on blueprint:
13-
post_routes_bp = APIBlueprint("post_routes", __name__)
13+
post_routes_bp = APIBlueprint("post_routes", __name__, tag="Post_Routes")
1414

1515
# Store-backed blueprint. Only registered when storage is enabled
1616
# (see app.create_app), so the ID-based routes are unreachable by default.
17-
minio_post_routes_bp = APIBlueprint("minio_post_routes", __name__)
17+
# Shares the always-on blueprint's docs tag so Swagger shows one POST group.
18+
minio_post_routes_bp = APIBlueprint("minio_post_routes", __name__, tag="Post_Routes")
1819

1920

2021
class ValidateCrate(Schema):

tests/test_app_factory.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,17 @@ def test_incoming_request_id_is_echoed():
8181
)
8282

8383
assert response.headers["X-Request-ID"] == "caller-supplied-id"
84+
85+
86+
def test_openapi_groups_posts_under_one_tag_with_unique_tags():
87+
"""Both POST endpoints share one docs group and the spec has no duplicate tags."""
88+
app = create_app(settings=Settings.from_env(_storage_env()))
89+
spec = app.test_client().get("/openapi.json").json
90+
91+
tag_names = [tag["name"] for tag in spec["tags"]]
92+
assert len(tag_names) == len(set(tag_names))
93+
94+
paths = spec["paths"]
95+
assert paths["/v1/ro_crates/validate_metadata"]["post"]["tags"] == ["Post_Routes"]
96+
assert paths["/v1/ro_crates/{crate_id}/validation"]["post"]["tags"] == ["Post_Routes"]
97+
assert paths["/v1/ro_crates/{crate_id}/validation"]["get"]["tags"] == ["Get_Routes"]

0 commit comments

Comments
 (0)