FastAPI를 쓰다 보면 "URL 안에서 꼭 필요한 값"과 "필요하면 덧붙이는 값"을 나눠야 합니다. 경로(path) 파라미터는 /items/10처럼 URL 구조 안에서 특정 자원을 가리키는 필수 값입니다. 쿼리(query) 파라미터는 ?sort=latest처럼 조건을 추가로 전달하는 값입니다. 이 둘을 구분하면 URL이 읽기 쉬워지고, 문서에서도 필수 여부를 명확히 알려 줄 수 있습니다. 2편에서 만든 기본 서버를 그대로 사용하면서, 이번 글에서는 경로 파라미터와 쿼리 파라미터를 각각 어떻게 선언하고 어떤 상황에서 쓰면 좋은지 살펴봅니다.
이번 글에서 새로 나오는 용어
- 경로 파라미터:
/items/{id}처럼 URL 구조 안에 박혀 있는 필수 값으로, 어떤 자원을 가리키는지 정해 주기 때문에 이번 글의 첫 실습 대상입니다. - 쿼리 파라미터:
?sort=latest처럼 필요할 때만 붙이는 옵션 값으로, 정렬·검색 조건을 표현할 때 글에서 반복 사용합니다. - 422 응답: FastAPI가 잘못된 타입이나 누락된 값을 받았을 때 돌려주는 “검증 실패” 코드로, 파라미터를 나눴을 때 어떤 검증이 자동으로 되는지 보여 줍니다.
실습 카드
- 예상 소요 시간: 35분
- 사전 준비: 2편에서 만든 FastAPI 기본 앱
- 실습 목표: 경로·쿼리 파라미터를 선언하고 Swagger UI에서 검증한다
이 글에서 할 것
- 경로 파라미터 선언과 타입 변환 보기
- 필수/선택 쿼리 파라미터 선언하기
uv run fastapi dev main.py로 실습하며 Swagger UI에서 비교하기
경로 파라미터는 URL 구조의 일부다
경로(path) 파라미터는 URL 구조 안에서 꼭 필요한 값입니다. 예를 들어 /items/123에서 123은 특정 아이템을 가리키는 필수 값입니다.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
타입 힌트를 int로 적어 두면 FastAPI가 자동으로 변환해 줍니다. 숫자가 아닌 값이 들어왔을 때는 422 응답을 주어 잘못된 요청임을 알려 줍니다.
쿼리 파라미터는 유연한 옵션이다
쿼리(query) 파라미터는 ?key=value 형태로 붙는 값입니다. 선택적으로 정렬 기준이나 페이지 크기를 전달할 때 쓰기 좋습니다.
@app.get("/items")
def list_items(q: str | None = None, limit: int = 10):
base_items = ["pencil", "pen", "notebook", "eraser"]
filtered = [item for item in base_items if not q or q.lower() in item.lower()]
return filtered[:limit]
q는 기본값이None이라 선택 파라미터가 됩니다.limit은 기본값 10으로 지정해서, 요청하지 않아도 10개까지만 보내도록 했습니다.
실전 예제: 스터디 팀 검색
동아리 관리 앱에서 팀명으로 경로 파라미터를, 정렬 기준을 쿼리 파라미터로 받는 패턴을 만들면 즉시 실전에 적용할 수 있습니다.
@app.get("/teams/{team_name}")
def get_team(team_name: str, sort: str = "latest"):
data = fetch_team(team_name)
order_key = "created_at" if sort == "latest" else "score"
return sorted(data["members"], key=lambda member: member[order_key], reverse=True)
이렇게 작성해 두면 URL이 GET /teams/racing?sort=score처럼 명확해지고, Swagger UI에서도 어느 값이 필수인지 바로 드러납니다.
문서 페이지에서 차이 보기
서버를 실행하고 /docs에 들어가면 경로 파라미터는 URL 부분에 입력칸이 나오고, 쿼리 파라미터는 별도의 입력 필드가 나타납니다.
uv run fastapi dev main.py
Swagger UI에서 GET /items/{item_id}를 눌러 보면 Path Parameters 섹션이 별도로 표시되고, GET /items에서는 Query Params 섹션이 나옵니다. 이 UI 차이만 봐도 두 파라미터의 위치가 다름을 바로 이해할 수 있습니다.
검증 규칙 더하기
쿼리 파라미터에도 검증 규칙을 더할 수 있습니다.
from fastapi import Query
@app.get("/search")
def search_items(keyword: str = Query(min_length=2, max_length=20)):
return {"keyword": keyword}
Query를 사용하면 길이, 정규식 등 다양한 조건을 붙일 수 있습니다. 문서 페이지에서도 조건이 자동으로 표시됩니다.
정리
- 경로 파라미터는 URL 구조의 필수 값이라 함수 인자에 중괄호 이름과 같은 이름으로 선언합니다.
- 쿼리 파라미터는
?key=value형태로 붙는 옵션이라 기본값을 주면 선택 파라미터가 됩니다. - 타입 힌트와
Query헬퍼로 검증 규칙을 선언하면 문서에도 그대로 노출됩니다.
왜 구분해야 하나
경로와 쿼리의 역할을 나누면 API가 요구하는 정보가 명확해집니다. 클라이언트는 필수 값을 빠뜨리지 않고, 선택 옵션은 필요할 때만 덧붙일 수 있습니다. URL 공유나 캐싱도 쉬워져서 같은 요청을 여러 번 실험할 때 실수가 줄어듭니다.
실습
- 따라 하기:
/items/{item_id}와/items엔드포인트를 작성하고 Swagger UI로 각각 호출한다. - 확장하기:
GET /search에min_length검증을 붙여 1글자 검색 시 422 응답을 확인한다. - 디버깅: 잘못된 타입을 전달해 422가 나는 이유를 응답 본문에서 찾아 설명한다.
- 완료 기준: 경로/쿼리 파라미터 차이를 말로 설명하고, 예제 코드가 200/422 응답을 의도대로 반환한다.
마무리
경로와 쿼리 파라미터를 구분하는 것만으로도 API 설계가 훨씬 명확해집니다. 다음 글에서는 요청 본문(body)을 받아 복잡한 데이터를 FastAPI에서 어떻게 다루는지, Pydantic 모델을 활용해 살펴보겠습니다.
💬 댓글
이 글에 대한 의견을 남겨주세요