Python/FastAPI

[FastAPI] FastAPI 튜토리얼 (2) - 매개변수

ready-go 2023. 7. 14. 19:47

Path Operation

Path는 URL에서 도메인 뒤에 붙는 경로를 말한다. 예를 들어, 아래와 같은 URL이 있다고 하자.

https://example.com/items/foo

여기서 Path에 해당하는 것은

/items/foo

 

Operation은 HTTP 메소드를 말한다. GET, POST, PUT, DELETE 이외에도 OPTIONS, HEAD, PATCH 등이 있다.

 

이렇게 Path와 Operation의 조합을 Path Operation이라고 한다. FastAPI에서는 특정한 Path Operation으로 요청이 왔을 때 실행할 함수를 decorator로 FastAPI 인스턴스에 등록할 수 있다.

@app.get("/")
def hello_world():
	return {"Hello": "World!"}

이 때, 같은 Path Operation이라도 사용자의 입력에 따라 다양한 동작을 수행할 수 있다. 이번 글에서는 FastAPI에서 사용자의 입력을 받는 방법을 알아보자.

 

Path Parameter

먼저, Path Parameter는 Path의 특정 부분을 매개변수로 받는 방법이다. 예를 들어, 쇼핑몰에서 판매중인 상품을 Item이라고 하자. 각 상품의 상세 정보를 얻고싶다면 해당 상품을 특정할 수 있는 id가 필요하다. 이런 경우, 각 상품의 id별로 함수를 만들어야 한다면 새로운 상품을 등록할 때마다 새로운 함수를 작성해야 할 것이고, 매번 서버를 재시작해야 할 것이다.

 

사용법

대부분의 웹 프레임워크는 Path의 일부를 Path Parameter로 사용할 수 있는 방법을 제공한다. FastAPI도 마찬가지로, 아래와 같이 사용할 수 있다.

@app.get("/items/{item_id}")
def read_item(item_id):
	return {"item_id": item_id}

 

Path에서 Path Parameter로 사용할 부분을 중괄호 안에 넣고, 함수의 parameter를 같은 이름으로 만들어주면 된다. 이제 직접 테스트를 해보자. /items/abcd로 GET 요청을 보내면 아래와 같은 응답이 온다.

{"item_id": "abcd"}

이번에는 /items/123으로 GET 요청을 보내면 마찬가지로 응답이 온다.

{"item_id": "123"}

응답을 보면 123이 문자로 인식되는 것을 알 수 있다. 요청을 숫자로 요청을 보냈지만 서버는 그것을 숫자로 처리해야할지, 문자열로 처리해야할지 알지 못한다. 따라서 타입에 대한 힌트를 제공해야 item_id를 숫자로 사용할 수 있다.

 

타입이 있는 path parameter

@app.get("/items/{item_id}")
def read_item(item_id: int):
	return {"item_id": item_id}

이제, 같은 요청을 보냈을 때 숫자로 응답이 온다.

{"item_id": 123}

이렇게 타입을 명시하는 경우, 타입이 맞지 않으면 에러가 난다. /items/abcd으로 GET 요청을 해보면 에러가 나는 것을 확인할 수 있다.

 

Enum

Enum을 사용해 미리 정의된 값으로만 parameter를 받을 수도 있다. 예를 들어, Item의 타입이 음식과 음료로 나누어진다고 하자. 아래와 같이 Enum 클래스를 정의할 수 있다.

from enum import Enum


class ItemType(str, Enum):
	food = "food"
	beverage = "beverage"

이제, path parameter를 통해 ItemType을 받아보자.

@app.get("/items/{item_type}")
def item_type(item_type: ItemType):
	return {"item_type": item_type}

이제 /items/food로 GET 요청을 보내면 아래와 같은 응답이 온다.

{"item_type":"food"}

만약 food와 beverage가 아닌 값을 보내면 에러가 발생한다.

 

Query Parameter

Query Parameter는 URL 끝에 ? 뒤에 붙은 것들을 말한다. 예를 들면 아래와 같은 형식이다.

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

위 요청에서 skip이라는 query parameter로 0, limit이라는 query parameter로 10이 들어왔다. Query Parameter는 이처럼 key-value로 이루어진 값이다.

 

사용법

FastAPI에서는 함수의 parameter로 선언된 값들 중 path parameter가 아닌 것들을 query parameter로 취급한다. 아래와 같은 함수를 보자.

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

위 요청에 의하면 items 리스트의 0부터 9까지 10개의 값을 리턴한다.

 

기본값

Query parameter는 기본값을 정의하는 경우가 많다. 기본값을 정의하면 query parameter를 주지 않고도 요청을 보낼 수 있다. 위 함수에 기본값을 정의하면 아래와 같다.

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

이제 요청시에 query parameter가 없어도 잘 동작한다.

http://127.0.0.1:8000/items/

위 요청은 아래와 완전히 동일하다.

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

둘 중 하나만 요청해도 된다. 예를 들어, 위 요청에서 skip이 0이므로 기본값과 같다. 따라서 아래와 같이 보내도 동일한 결과가 나온다.

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

 

Request Body

마지막으로, Request Body는 HTTP 요청의 body에 실어보내는 데이터를 의미한다. 일반적으로 API를 통해 데이터를 주고받을 때 JSON 형식의 데이터를 통해 데이터를 주고받는다.

 

사용법

JSON 형식의 데이터를 입력으로 받기 위해서 구조화된 클래스를 정의해야한다. 이 클래스는 pydantic 패키지의 BaseModel을 상속받는다.

from pydantic import BaseModel


class Item(BaseModel):
	name: str
	description: str | None = None
	price: float
	tax: float | None = None

이제 이렇게 정의된 클래스를 함수의 메소드 파라미터로 정의하면 된다.

@app.post("/items/")
def create_item(item: Item):
	return item

이제 item의 구조와 똑같은 구조를 가진 JSON 데이터를 HTTP body로 갖는 POST 요청을 보낼 수 있다.

{
  "name": "item1",
  "description": "1번 아이템",
  "price": 300.0,
  "tax": 10.0
}

여기서 description과 tax는 None이 될 수도 있는 optional한 속성이기 때문에 아래와 같은 JSON도 유효하다.

{
  "name": "item1",
  "price": 300.0
}

 

3줄 요약

  1. URL의 Path와 HTTP 메소드의 operation을 합쳐서 path operation을 정의할 수 있다
  2. API에서 데이터를 입력받는 방법은 Path Parameter, Query Parameter, Request Body가 있다
  3. FastAPI는 함수 파라미터를 정의하는 것만으로 간단하게 입력을 받을 수 있는 방법을 제공한다