FastAPI 데이터 전송(post) 및 수정(put)

생각하는 마리오네트·2023년 10월 9일
0

삽지니어링

목록 보기
7/10
post-thumbnail

본격적인 포스팅에 들어가기전 간단하게 HTTP를 통한 통신 메서드4가지를 정리하려고 한다.
Client즉, 우리의 컴퓨터가 Server와 통신하기 위해서는 HTTP의 method를 사용해야하는데 이때 주로 사용되는
것이 GET, POST, PUT, DELETE이다.

GET은 조회를 하는것 즉, 서버에 있는 데이터를 읽는 것이다.
POST는 서버에 데이터를 생성하는것, 등록하는것이다.
PUT은 서버에 있는 데이터를 변경하고 수정하는것이다.
DELETE는 서버에 있는 데이터를 삭제하는 것이다.

Request Body

클라이언트에서 API를 통하여 데이터를 보내고 싶을때, request body를 사용하여 보낼 수 있는데, request body를 정의를 할때 Pydantic과 함께 사용할 수 있다.

생성, 수정, 삭제 같은 경우에는 상황에 맞는 http method와 함께 response를 하면되지만, GET메서드와 함께 body를 보내는 것은 이상한 행동임을 이해할것이다...

** Pydentic의 BaseModel클래스를 상속받는 data model을 선언해보자

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

app = FastAPI()

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

data model을 선언할때에도 query파라미터를 선언할때와 마찬가지로 필수와 선택, default값 등을 부여할 수 있다.

위의 내용을 JSON으로 변환되면 아래와 같다.

    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5

이때, description과 tax는 optional하기 때문에 제외해도 무관하다.

결과정리

파이썬의 타입 선언과 마찬가지로, FastAPI에서는

  • request body로 부터 JSON을 읽는다.
  • model 클래스를 통해 상응하는 타입으로 전환한다.
  • 데이터를 validate한다.
    - 만약에 invalid한다면, 에러와 함께 어디가 틀렸는지 알려준다.
  • 파라미터로 부터 받은 data를 받는(위의 예시에서 item을 의미한다.)
  • model 클래스로부터 JSON Schema를 만든다.
  • 해당 Schema는 OpenAPI schema와 API문서등에 도움을 준다.

활용

1. dict활용 : API함수 안에서 model의 모든 속성에 접근할 수 있다.

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict

2. path파라미터와 request body를 동시에 받을 수 있다.

(여기서 FastAPI는 자동적으로 함수의 파라미터에서 path로 부터 받은 것은 path 파라미터로 인식을 하고, Pydantic 모델로 선언된것은 request body로 인식한다.)

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

app = FastAPI()

@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.dict()}

마지막 return값에 items.dict() 앞에 **가 붙은것이 보인다.
** 이 기호는 Python에서 dictionary unpacking 또는 dictionary expansion이라고 불리는 문법으로 이 기호를 사용하게 되면 딕셔너리의 키-값 쌍을 다른 딕셔너리에 풀어서(펼쳐서)병합할 수 있다.

예를 들어 아래와 같은 경우가 있다.

dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}

merged_dict = {**dict1, **dict2}
print(merged_dict)  # 출력: {'a': 1, 'b': 2, 'c': 3, 'd': 4}

우리의 예시의 경우는 item을 dict형태로 바꾸었으며 return되는 dict에 펼쳐져서 나오는 형태로
만들기 위해서 기호를 넣은것이다.

3. path파라미터와 query파라미터와 request body를 혼합할 수 있다.

  • path에 선언된 파라미터 : path parameters로 인식
  • path에 없고 타입이 지정된 파라미터 : query parameters로 인식
  • Pydantic model로 타입이 선언된 파라미터 : request body로 인식
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

app = FastAPI()

@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item, q: Union[str, None] = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result

profile
문제를해결하는도구로서의"데이터"

0개의 댓글