python / / 2024. 8. 16. 09:29

[fastapi] 기본 자료형 외 다양한 데이터 타입 처리하기

FastAPI는 Python의 기본 자료형(str, int, float, bool) 외에도 다양한 데이터 타입을 지원하여 API 개발을 더욱 유연하게 해준다. 이번 글에서는 FastAPI에서 UUID, datetime, date, time, timedelta, frozenset, bytes, decimal 등과 같은 다양한 데이터 타입을 처리하는 방법에 대해 알아보자.

1. UUID

UUID(Universally Unique Identifier)는 고유 식별자이다. FastAPI는 UUID 타입을 직접 지원하며, Pydantic을 사용하여 모델에서 쉽게 처리할 수 있다.

from fastapi import FastAPI
from pydantic import BaseModel
from uuid import UUID

app = FastAPI()

class Item(BaseModel):
    id: UUID
    name: str

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

위 코드에서 id 필드는 UUID 타입으로 지정되어 있다. 클라이언트는 다음과 같은 형식의 UUID 데이터를 전송할 수 있다.

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "Sample Item"
}

만일 id가 32자리가 아니라면 아래와 422 Unprocessable Entity 오류가 발생한다.

{
  "detail": [
    {
      "type": "uuid_parsing",
      "loc": [
        "body",
        "id"
      ],
      "msg": "Input should be a valid UUID, invalid group length in group 4: expected 12, found 11",
      "input": "123e4567-e89b-12d3-a456-42661417400",
      "ctx": {
        "error": "invalid group length in group 4: expected 12, found 11"
      }
    }
  ]
}

2. datetime

datetime은 날짜와 시간을 포함한 데이터 타입이다. FastAPI는 datetime 타입을 지원하며, 이를 통해 날짜와 시간 정보를 처리할 수 있다.

from fastapi import FastAPI
from pydantic import BaseModel
from datetime import datetime

app = FastAPI()

class Event(BaseModel):
    name: str
    event_datetime: datetime

@app.post("/events/")
async def create_event(event: Event):
    return event

클라이언트는 다음과 같은 형식으로 datetime 데이터를 전송할 수 있습니다.

{
  "name": "Conference",
  "event_datetime": "2024-08-16T10:00:00"
}

또는 아래와 같이 전송해도 된다.

{
  "name": "Conference",
  "event_datetime": "2024-08-16 10:00:00"
}

3. date

date 타입은 날짜만을 포함하며, 시간 정보는 포함하지 않는다. date 타입은 종종 생년월일, 이벤트 날짜 등의 데이터를 처리할 때 사용된다.

from fastapi import FastAPI
from pydantic import BaseModel
from datetime import date

app = FastAPI()

class Event(BaseModel):
    name: str
    event_date: date

@app.post("/events/")
async def create_event(event: Event):
    return event

이 경우 클라이언트는 다음과 같은 데이터를 전송할 수 있다.

{
  "name": "Birthday Party",
  "event_date": "2024-08-16"
}

4. time

time 타입은 시간만을 포함하며, 날짜 정보는 포함하지 않는다. 특정 시간대에 대한 데이터 처리에 유용하다.

from fastapi import FastAPI
from pydantic import BaseModel
from datetime import time

app = FastAPI()

class Schedule(BaseModel):
    name: str
    start_time: time

@app.post("/schedules/")
async def create_schedule(schedule: Schedule):
    return schedule

클라이언트는 다음과 같은 형식으로 time 데이터를 전송할 수 있다.

{
  "name": "Morning Run",
  "start_time": "06:30:00"
}

5. timedelta

timedelta는 두 날짜 또는 시간 간의 차이를 나타낸다. FastAPI는 이를 지원하여 시간 간격 데이터를 처리할 수 있다.

from fastapi import FastAPI
from pydantic import BaseModel
from datetime import timedelta

app = FastAPI()

class Task(BaseModel):
    name: str
    duration: timedelta

@app.post("/tasks/")
async def create_task(task: Task):
    return task

클라이언트는 다음과 같은 데이터를 전송할 수 있다.

{
  "name": "Workout",
  "duration": "1:30:00"  
}

6. frozenset

frozenset은 불변 집합으로, FastAPI에서 다루기 위해 Pydantic의 지원을 받는다. frozenset은 고유한 값을 유지하면서도 변하지 않도록 할 때 유용하다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class ItemCollection(BaseModel):
    tags: frozenset[str]

@app.post("/collections/")
async def create_collection(collection: ItemCollection):
    return collection

클라이언트는 다음과 같은 형식으로 frozenset 데이터를 전송할 수 있다.

{
  "tags": ["red", "blue", "green"]
}

7. bytes

bytes는 이진 데이터(예: 파일의 내용)를 처리하는 데 사용된다. FastAPI는 바이트 데이터 처리를 기본적으로 지원한다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class FileData(BaseModel):
    file_name: str
    data: bytes

@app.post("/files/")
async def upload_file(file_data: FileData):
    return {"file_name": file_data.file_name, "data_length": len(file_data.data)}

클라이언트는 이진 데이터를 Base64로 인코딩하여 전송할 수 있다.

{
  "file_name": "example.txt",
  "data": "SGVsbG8gV29ybGQh"  # "Hello World!"의 Base64 인코딩
}

8. decimal

decimal.Decimal은 고정 소수점과 부동 소수점 간의 차이로 인해 발생할 수 있는 부정확성을 피하기 위해 정확한 소수점 계산이 필요한 경우 사용된다.

from fastapi import FastAPI
from pydantic import BaseModel
from decimal import Decimal

app = FastAPI()

class Product(BaseModel):
    name: str
    price: Decimal

@app.post("/products/")
async def create_product(product: Product):
    return product

클라이언트는 다음과 같은 데이터를 전송할 수 있다.

{
  "name": "Laptop",
  "price": "1999.99"
}

9. 모델 생성하지 않고 body로 전송

모델을 만들지 않고 Annotated를 사용하여 아래와 같이 한번에 전송할 수도 있다.

@app.post("/items/{item_id}")
async def read_items(
    item_id: UUID,
    start_datetime: Annotated[datetime, Body()],
    end_datetime: Annotated[datetime, Body()],
    process_after: Annotated[timedelta, Body()],
    repeat_at: Annotated[time | None, Body()] = None,
):
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime,
        "end_datetime": end_datetime,
        "process_after": process_after,
        "repeat_at": repeat_at,
        "start_process": start_process,
        "duration": duration,
    }

또는 Annotated를 사용하지 않고 만드는 방법은 아래와 같다.

@app.post("/items/{item_id}")
async def read_items(
    item_id: UUID,
    start_datetime: datetime = Body(),
    end_datetime: datetime = Body(),
    process_after: timedelta = Body(),
    repeat_at: time | None = Body(),
):
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime,
        "end_datetime": end_datetime,
        "process_after": process_after,
        "repeat_at": repeat_at,
        "start_process": start_process,
        "duration": duration,
    }

클라이언트에서는 다음과 같이 데이터를 전송할 수 있다.

{
  "start_datetime": "2024-08-16T10:00:00",
  "end_datetime": "2024-08-16T12:00:00",
  "process_after": "0:20:00",
  "repeat_at": "06:30:00"
}

참고

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유