Skip to content

Commit

Permalink
Do not allow duplicate tag names (OpenAPI object)
Browse files Browse the repository at this point in the history
Addresses issue #5552
  • Loading branch information
aradipe committed Oct 28, 2022
1 parent f67b19f commit e3a9696
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
10 changes: 9 additions & 1 deletion fastapi/openapi/models.py
Expand Up @@ -2,7 +2,7 @@
from typing import Any, Callable, Dict, Iterable, List, Optional, Union

from fastapi.logger import logger
from pydantic import AnyUrl, BaseModel, Field
from pydantic import AnyUrl, BaseModel, Field, validator

try:
import email_validator # type: ignore
Expand Down Expand Up @@ -400,6 +400,14 @@ class OpenAPI(BaseModel):
class Config:
extra = "allow"

@validator("tags")
def check_foo(cls, v): # type: ignore
unique_names = set()
assert not any(
t.name in unique_names or unique_names.add(t.name) for t in v # type: ignore
), "Tag names must be unique"
return v


Schema.update_forward_refs()
Operation.update_forward_refs()
Expand Down
5 changes: 4 additions & 1 deletion fastapi/openapi/utils.py
Expand Up @@ -444,5 +444,8 @@ def get_openapi(
output["components"] = components
output["paths"] = paths
if tags:
output["tags"] = tags
# discard tags with non-unique names as it is against the OpenAPI spec
# https://swagger.io/specification/#openapi-object
names = set()
output["tags"] = [t for t in tags if t["name"] not in names and not names.add(t["name"])] # type: ignore
return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore
22 changes: 22 additions & 0 deletions tests/test_duplicate_openapi_tags.py
@@ -0,0 +1,22 @@
"""Test case for possible tag duplication at OpenAPI object level"""

from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI(
openapi_tags=[
{"name": "items", "description": "items1"},
{"name": "items", "description": "items2"},
]
)

client = TestClient(app)


def test_openapi_for_duplicates():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
tag_list = response.json()["tags"]
assert len(tag_list) == 1
assert tag_list[0]["name"] == "items"
assert tag_list[0]["description"] == "items1"

0 comments on commit e3a9696

Please sign in to comment.