5. Response model
응답 모델
이제 입력을 어떻게 주는지 말고 응답이 어떻게 오는지 확인해보자. 간단하게 get 에 response_model을 추가하면 된다.
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class User(BaseModel):
name: str
password: str
avatar_url: Optional[HttpUrl] = None
@app.get("/users/me", response_model=User)
def get_user(user: User):
return user
swagger에서 sucessful response 의 스키마를 보면 아래와 같다.
이제 터미널에서 응답이 어떻게 오는지 살펴보자.
(fastapi) PS D:\workspace> http :8000/users/me name=syj password=1234 avatar_url=example.com
HTTP/1.1 405 Method Not Allowed
allow: GET
content-length: 31
content-type: application/json
date: Sat, 13 Aug 2022 10:39:10 GMT
server: uvicorn
{
"detail": "Method Not Allowed"
}
json body가 있으면 알아서 post 라고 변환을 해주기 떄문에 일어나는 오류이다. 아래와 같이 해결할 수 있다.
(fastapi) PS D:\workspace> http -v :8000/users/me name=syj password=1234 avatar_url=example.com
POST /users/me HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 64
Content-Type: application/json
Host: localhost:8000
User-Agent: HTTPie/3.2.1
{
"avatar_url": "example.com",
"name": "syj",
"password": "1234"
}
HTTP/1.1 405 Method Not Allowed
allow: GET
content-length: 31
content-type: application/json
date: Sat, 13 Aug 2022 10:41:15 GMT
server: uvicorn
{
"detail": "Method Not Allowed"
}
이 또한 POST 로 바꿔서 요청을 보내는데 결과를 뱉긴한다. 이는 우리가 GET으로 앱을 만들었기 때문이다. 결과적으로 request body를 사용할 때에는 post를 사용해야 한다.
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class User(BaseModel):
name: str
password: str
avatar_url: Optional[HttpUrl] = None
@app.post("/users/me", response_model=User)
def get_user(user: User):
return user
(fastapi) PS D:\workspace> http :8000/users/me name=syj password=1234
HTTP/1.1 200 OK
content-length: 50
content-type: application/json
date: Sat, 13 Aug 2022 10:43:43 GMT
server: uvicorn
{
"avatar_url": null,
"name": "syj",
"password": "1234"
}
응답모델과 요청모델 분리
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class CreateUser(BaseModel):
name: str
password: str
avatar_url: Optional[HttpUrl] = None
class GetUser(BaseModel):
name: str
avatar_url: Optional[HttpUrl] = None
@app.post("/users", response_model=GetUser) # 응답 모델
def create_user(user: CreateUser): # 요청 모델
return user
이렇게 요청 모델에서는 password를 보내지만 응답 모델에서는 password를 보여주지 않는 것을 확인할 수 있다.
(fastapi) PS D:\workspace> http :8000/users name=syj password=1234
HTTP/1.1 200 OK
content-length: 32
content-type: application/json
date: Sat, 13 Aug 2022 10:47:23 GMT
server: uvicorn
{
"avatar_url": null,
"name": "syj"
}
중복을 최소화 하기 위해 응답 모델을 상속받아 요청 모델을 만들면 된다.
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class GetUser(BaseModel):
name: str
avatar_url: Optional[HttpUrl] = None
class CreateUser(GetUser):
password: str
@app.post("/users", response_model=GetUser) # 응답 모델
def create_user(user: CreateUser): # 요청 모델
return user
응답 코드
HTTP는 다양한 상태 코드를 가진다. API 호출에 성공했을 경우 기본값인 200을 반환한다. 300번대는 redirect, 400번 대는 클라이언트가 잘못되었을 떄, 500번대는 서버가 잘못되었을때 주는 응답 코드이다.
이번에는 API가 잘 호출되었을 떄 201을 뱉는 사용자 응답 코드를 만들어 본다.
from typing import Optional
from fastapi import FastAPI, status
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class GetUser(BaseModel):
name: str
avatar_url: Optional[HttpUrl] = None
class CreateUser(GetUser):
password: str
@app.post("/users", response_model=GetUser, status_code=201) # 응답 모델
def create_user(user: CreateUser): # 요청 모델
return user
201 Created 라는 응답이 오는 것을 볼 수 있다.
(fastapi) PS D:\workspace> http :8000/users name=syj password=1234
HTTP/1.1 201 Created
content-length: 32
content-type: application/json
date: Sat, 13 Aug 2022 10:58:12 GMT
server: uvicorn
{
"avatar_url": null,
"name": "syj"
}