쿼리 파라미터 (Query Parameters)

쿼리 파라미터 (Query Parameters)

경로 파라미터(path parameter)의 일부가 아닌 함수 파라미터를 선언하면, FastAPI는 그걸 자동으로 "쿼리" 파라미터로 해석해요.

from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]

@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]

쿼리(Query)는 URL에서 ? 뒤에 나오는 키-값 쌍의 모음이고, 각 쌍은 & 문자로 구분돼요.

예를 들어 다음 URL에서

http://127.0.0.1:8000/items/?skip=0&limit=10

쿼리 파라미터는 이렇게 돼요:

  • skip: 값이 0
  • limit: 값이 10

쿼리 파라미터는 URL의 일부라서 "자연스럽게" 문자열로 처리돼요.

그런데 위 예시처럼 Python 타입(여기서는 int)으로 선언하면, 그 타입으로 변환되고 그 타입에 맞게 검증돼요.

경로 파라미터에 적용되던 과정은 쿼리 파라미터에도 그대로 적용돼요:

  • 에디터 지원 (당연하게도)
  • 데이터 "파싱(parsing)"
  • 데이터 검증
  • 자동 문서화

기본값 (Defaults)

쿼리 파라미터는 경로의 고정된 일부가 아니어서, 선택적(optional)일 수 있고 기본값도 가질 수 있어요.

위 예시에서 skip=0limit=10이 기본값이었죠.

그래서 이 URL로 접속하는 건

http://127.0.0.1:8000/items/

이 URL로 접속하는 것과 같아요:

http://127.0.0.1:8000/items/?skip=0&limit=10

하지만 예를 들어 이렇게 접속하면

http://127.0.0.1:8000/items/?skip=20

함수의 파라미터 값은 이렇게 돼요:

  • skip=20: URL에서 직접 설정했으니까
  • limit=10: 기본값이니까

선택적 파라미터 (Optional parameters)

같은 방식으로, 기본값을 None으로 설정하면 선택적 쿼리 파라미터를 선언할 수 있어요:

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None):
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}

이 경우 함수 파라미터 q는 선택적이고, 기본값은 None이 돼요.

Tip

여기서 FastAPI가 경로 파라미터인 item_id와 아닌 q를 구분해 내는 것도 눈여겨보세요. q는 경로 파라미터가 아니니까 쿼리 파라미터로 처리돼요.

쿼리 파라미터 타입 변환 (Query parameter type conversion)

bool 타입도 선언할 수 있고, 변환이 적용돼요:

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None, short: bool = False):
    item = {"item_id": item_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item

이 경우 이런 URL로 접속하면

http://127.0.0.1:8000/items/foo?short=1

또는

http://127.0.0.1:8000/items/foo?short=True

또는

http://127.0.0.1:8000/items/foo?short=true

또는

http://127.0.0.1:8000/items/foo?short=on

또는

http://127.0.0.1:8000/items/foo?short=yes

또는 대소문자를 바꾼 다른 어떤 조합(전부 대문자, 첫 글자만 대문자 등)이든, 함수는 short 파라미터를 불리언 값 True로 받아요. 그 외에는 False로 처리돼요.

여러 개의 경로·쿼리 파라미터 (Multiple path and query parameters)

경로 파라미터와 쿼리 파라미터를 동시에 여러 개 선언할 수 있고, FastAPI는 어떤 게 어떤 건지 구분해요.

그리고 특정 순서로 선언할 필요도 없어요. 이름으로 구분되거든요:

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
    user_id: int, item_id: str, q: str | None = None, short: bool = False
):
    item = {"item_id": item_id, "owner_id": user_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item

필수 쿼리 파라미터 (Required query parameters)

경로가 아닌 파라미터(지금까지는 쿼리 파라미터만 봤죠)에 기본값을 선언하면, 그 파라미터는 필수가 아니에요.

특정 값을 넣지 않고 그냥 선택적으로 만들고 싶다면 기본값을 None으로 설정하면 돼요.

하지만 쿼리 파라미터를 필수로 만들고 싶다면, 기본값을 선언하지 않기만 하면 돼요:

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_user_item(item_id: str, needy: str):
    item = {"item_id": item_id, "needy": needy}
    return item

여기서 쿼리 파라미터 needystr 타입의 필수 쿼리 파라미터예요.

브라우저에서 이런 URL을 열면

http://127.0.0.1:8000/items/foo-item

필수 파라미터인 needy를 넣지 않았으니 이런 오류를 보게 돼요:

{
  "detail": [
    {
      "type": "missing",
      "loc": [
        "query",
        "needy"
      ],
      "msg": "Field required",
      "input": null
    }
  ]
}

needy는 필수 파라미터니까 URL에 설정해 줘야 해요:

http://127.0.0.1:8000/items/foo-item?needy=sooooneedy

이렇게 하면 제대로 동작해요:

{
    "item_id": "foo-item",
    "needy": "sooooneedy"
}

그리고 당연히, 필수인 파라미터와 기본값이 있는 파라미터, 완전히 선택적인 파라미터를 섞어서 선언할 수도 있어요:

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_user_item(
    item_id: str, needy: str, skip: int = 0, limit: int | None = None
):
    item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
    return item

이 경우 쿼리 파라미터가 3개 있어요:

  • needy: 필수 str
  • skip: 기본값이 0int
  • limit: 선택적 int

Tip

경로 파라미터에서 했던 것과 같은 방식으로 Enum도 사용할 수 있어요.