본문 바로가기
개발/FastAPI

[FastAPI] FastAPI 시작하기 Response Model ~ File 요청

by devhooney 2023. 5. 17.
728x90

회사에서 Python + FastAPI로 개발을 하게 되었다.

그래서 공식문서를 훑어보았다.

 

1. Return Type

API 호출 후 return 해줄 때 FastAPI에서 검증을 거친다. 데이터가 유효하지 않은 경우 (예: 필드가 누락된 경우)는 앱 코드가 제대로 작동하지 않거나 예상한대로 반환하지 않는 것을 의미하므로, 잘못된 데이터를 반환하는 대신 서버 오류를 반환한다. 이렇게 함으로써 사용자와 클라이언트는 예상한 데이터와 데이터 구조를 정확히 수신할 수 있음을 확신할 수 있다.

- main.py

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


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


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

# 이렇게도 표현 가능

@app.post("/items/", response_model=Item)
async def create_item2(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items2() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]

 

2. Return Type - Data Filtering

새로운 User를 생성하고 Return으로 그 User를 보내준다면, 비밀번호를 보내서는 안된다. 이럴 때 Return 타입을 두 개 만들어도 되지만, 상속을 해서 중복 코드 작성을 줄일 수 있다.

- main.py

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user

 

Swagger에서 확인하면 UserIn UserOut의 차이를 확인할 수 있다.

 

3. 응답 상태 코드

응답 모델과 같은 방법으로, 어떤 경로 작동이든 status_code 매개변수를 사용하여 응답에 대한 HTTP 상태 코드를 선언할 수 있다.

- main.py

from fastapi import FastAPI

app = FastAPI()


@app.post("/items/", status_code=201)
async def create_item(name: str):
    return {"name": name}

*참고

  • **1xx** 상태 코드는 "정보"용입니다. 이들은 직접적으로는 잘 사용되지는 않습니다. 이 상태 코드를 갖는 응답들은 본문을 가질 수 없습니다.
  • **2xx** 상태 코드는 "성공적인" 응답을 위해 사용됩니다. 가장 많이 사용되는 유형입니다.
    • 200 은 디폴트 상태 코드로, 모든 것이 "성공적임"을 의미합니다.
    • 다른 예로는 201 "생성됨"이 있습니다. 일반적으로 데이터베이스에 새로운 레코드를 생성한 후 사용합니다.
    • 단, 204 "내용 없음"은 특별한 경우입니다. 이것은 클라이언트에게 반환할 내용이 없는 경우 사용합니다. 따라서 응답은 본문을 가질 수 없습니다.
  • **3xx** 상태 코드는 "리다이렉션"용입니다. 본문을 가질 수 없는 304 "수정되지 않음"을 제외하고, 이 상태 코드를 갖는 응답에는 본문이 있을 수도, 없을 수도 있습니다.
  • **4xx** 상태 코드는 "클라이언트 오류" 응답을 위해 사용됩니다. 이것은 아마 가장 많이 사용하게 될 두번째 유형입니다.
    • 일례로 404 는 "찾을 수 없음" 응답을 위해 사용합니다.
    • 일반적인 클라이언트 오류의 경우 400 을 사용할 수 있습니다.
  • **5xx** 상태 코드는 서버 오류에 사용됩니다. 이것들을 직접 사용할 일은 거의 없습니다. 응용 프로그램 코드나 서버의 일부에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다

 

4. Form Data

from typing import Annotated

from fastapi import FastAPI, Form

app = FastAPI()


@app.post("/login/")
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
    return {"username": username}

Form 으로 전송됐을 때 Parameter를 받는 방법.

 

5. 파일 요청

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes = File()):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}

UploadFile 은 다음과 같은 어트리뷰트가 있다

  • filename : 문자열(str)로 된 업로드된 파일의 파일명 (예: myimage.jpg).
  • content_type : 문자열(str)로 된 파일 형식(MIME type / media type) (예: image/jpeg).
  • file : SpooledTemporaryFile (파일류 객체)은 "파일류" 객체를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일.

파일이 여러 개 일 경우

@app.post("/files/")
async def create_files(files: List[bytes] = File()):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(files: List[UploadFile]):
    return {"filenames": [file.filename for file in files]}

이 때는  bytes  List 또는 UploadFile 를 선언해서 사용해야 한다.

728x90