본문 바로가기

Fastapi

내맘대로 Fastapi docs 정리(Response Model, Extra Model)

 

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()

class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None

class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None

@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user

 

  •  user가 UserIn이라고 되어있어도 response_model이 UserOut이니까 password를 포함하지 않는다.
  • 만약 UserIn에서 username이 alias로 Username이라고 되어있고, UserOut이 그냥 username이라면 retunr값은 null이 된다. 

 

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []

items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}

@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
  • response_model에서 default 값을 지정할 수 있다.
  • response_model_exclude_unset=True -> response_model에서 input중에 없는 것은 return 안한다
  • response_model_exclude_defaults=True -> response_model에서 input model의 default값과 같은 값이면 제외.
  • response_model_exclude_none=True -> response_model에서 none 값이 있으면 제외.

 

@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]
  • 다음과 같이 response_model_exclude, response_model_include로 지정가능하며 str로 이루어진 집합.
  • include를 쓰면 response_model에서 무조건 포함시키고, exclude를 쓰면 무조건 배재한다.
  • {"name", "description"} == set(["name", "description"])

 

class UserBase(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None

class UserIn(UserBase):
    password: str

class UserOut(UserBase):
    pass

class UserInDB(UserBase):
    hashed_password: str

def fake_password_hasher(raw_password: str):
    return "supersecret" + raw_password

def fake_save_user(user_in: UserIn):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
    print("User saved! ..not really")
    return user_in_db

@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
    user_saved = fake_save_user(user_in)
    return user_saved
  •  보통 UserIn은 password를 포함하고, UserOut은 password를 포함하지 않고, UserInDB는 hash된 password를 가진다. 
  • model간 중복을 없애기 위해 서로 상속해준다.

 

@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
  • PlaneItem와 CarItem 중에 하나 반환.
  • python 3.10 버전이후부터는 Union 대신 | 를 써도 된다고 했는데, 위와 같은 경우에는 쓰면 안된다.

 

items = [
    {"name": "Foo", "description": "There comes my hero"},
    {"name": "Red", "description": "It's my aeroplane"},
]

@app.get("/items/", response_model=List[Item])
async def read_items():
    return items
  • 위와 같이 list로 넘겨줄 수 있다.
  • python 3.10이상부터는 내장함수 list를 사용할 수 있다.

 

@app.get("/keyword-weights/", response_model=Dict[str, float])
async def read_keyword_weights():
    return {"foo": 2.3, "bar": 3.4}
# pydantic 대신 key-value형태로 보낼 수 있다.
  • 위와 같이 dict로도 넘겨줄 수 있다.
  • python 3.10이상부터는 내장함수 dict를 사용할 수 있다.

 

from fastapi import FastAPI, status
app = FastAPI()

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

 

 

$ pip install python-multipart

from fastapi import FastAPI, Form

app = FastAPI()

@app.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)):
    return {"username": username}
    
# The way HTML forms (<form></form>) sends the data to the server normally uses 
# a "special" encoding for that data, it's different from JSON.
# form 안의 input에 name이 key 이고 value가 value인데 이것을 form 태그를 사용해서 전송을 하면
# Content-Type:application/x-www-form-urlencoded 방식으로 전달이 된다.
# 만약 files를 포함하면 multipart/form-data로 encoded된다.
# 둘다 body로 가는 것은 같지만 서버에서 받을 때 차이가 있는 것 같다.
# form태그가 아닌 axios.post에서 json을 첨부해서 보내는 경우는 
# Content-Type:application/json 으로 전달이 된다.