None이 될 수 있는 필드가 Swagger에서 제대로 표시되지 않는 문제

async def read_items(q: List[str] | None = Query())처럼 None이 될 수 있는 필드가 Swagger에서 제대로 표시되지 않는 현상
Posted on 2024-03-31 by GKSRUDTN99
FastAPI Python FastAPI

FastAPI 공식 가이드에 나와있는 대로

from typing import List
from fastapi import FastAPI, Query

app = FastAPI()

@app.get('/items')
async def read_items(q: List[str] | None = Query(default=None)):
    query_items = {"q": q}
    return query_items

어떤 Query Parameter가 필수값이 아닐 때, 그냥 None을 쓰면, Swagger 상에서 제대로 테스트 할 수 있는 형태로 필드가 표시되지 않습니다.

openapi.json 파일을 열어보면 이유를 알 수 있는데,

...
"parameters": [
  {
    "name": "q",
    "in": "query",
    "required": false,
    "schema": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "title": "Q"
    }
  }
],
...

Q의 타입이 array가 아니라, anyOf로 감싸진 형태가 되기 때문인데요,

이 경우에는 Swagger 상에서 Array 타입으로 표시되지 않기 때문에, 정상적인 테스트가 불가합니다.

어느 정도는 FastAPI / Swagger 쪽 버그라고 생각되지만, FastAPI Github의 한 이슈 workaround를 찾았습니다.

None 대신 SkipJsonSchema[None] 형태로 사용하는 것입니다.

from typing import List
from fastapi import FastAPI, Query
from pydantic.json_schema import SkipJsonSchema

app = FastAPI()

@app.get('/items')
async def read_items(q: List[str] | SkipJsonSchema[None] = Query(default=None)):
    query_items = {"q": q}
    return query_items

이렇게 바꾸고 openapi.json 파일을 확인하면,

"parameters": [
  {
    "name": "q",
    "in": "query",
    "required": false,
    "schema": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "title": "Q"
    }
  }
],

이렇게 Q의 타입이 array로 잘 잡히고, required도 false로 잘 들어가 있는 것을 확인할 수 있습니다.

여기서 주의할 점은,

= Query() 형태로 Default Value를 주지 않으면, Swagger 상에서 required=true인 상태로 표시될 수 있습니다.

따라서 Default Value를 명시해야 required=false로 표시됩니다.