FastAPI 공식 문서 공부하기!
pip install fastapi
# Production을 위해 'Uvicorn', 'Hypercorn'과 같은 ASGI server 필요
pip install "uvicorn[standard]"
먼저 웹 서버는 HTML/CSS/JS, img 파일 등과 같은 정적 컨테츠를 요청받아서 어플리케이션 서버를 거치지 않고 바로 응답해주거나, 동적 컨텐츠 요청을 WAS로 보내고 그 결과를 클라이언트에 전달하는 역활으 한다.
request -> Web Server(nginx, apache) -> WSGI server(gunicorn, uWSGU) -> Framework(django, flask)
기존의 django를 사용했을 때는 WSGI 서버를 주로 사용했는데, WSGI는 Websocket을 사용 할 수 없고 비동기를 사용할 수 없다는 단점이 있다.
이러한 WSGI의 단점을 극복하기 위해 나온 서버가 ASGI 서버로, WSGI의 상위호환 느낌이다. WSGI와 다르게 어플리케이션을 비동기
로 연결해주고 HTTP, HTTP/2, WebSocket와 같은 다양한 프로토콜
을 지원한다.
main.py
를 아래와 같이 생성from typing import Optional
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
async
, await
을 사용한다면from typing import Optional
from fastapi import FastAPI
app = FastAPI()
# 'await' 라이브러리는 오직 'async def' 안에서만 사용 가능
@app.get('/')
async def read_results():
results = await some_library()
return results
서버 실행 명령어
$ uvicorn main:app --reload
main
: main.py
파일을 뜻함app
: main.py
파일 안에 있는 app 오브젝트, app = FastAPI()
를 뜻함--reload
: 코드 변경 후 서버를 재시작 하도록 하는 명령어로 개발 단계에서만 사용한다FastAPI는 자동으로 API Documentation을 지원한다.
서버를 실행 시킨 후 http://127.0.0.1:8000/docs 에 접속하면 Swagger UI
에서 제공하는 Interactive API 문서를 볼수 있다.
http://127.0.0.1:8000/redoc 에 접속하면 Alternative API 문서를 볼수 있다.
FastAPI의 문서 자동화
FastAPI를 이용해 어플리케이션을 개발하면, 개발자가 만든 EndPoint외에 기본적으로 아래의 EndPoint가 자동으로 생성된다.
/docs
: FastAPI에 내장된 Swagger이 Interactive API 문서 생성redoc
: FastAPI에 내장된 ReDoc가 Alternative API 문서 생성openapi.json
: OpenAPI 규격에 맞는 json 파일 생성main.py
파일을 PUT
request로 부터 body를 받도록 수정해보자.
Pydantic
라이브러리를 활용해 body를 파이선 타입으로 정의한다.
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None
Pydantic 공식문서 : https://pydantic-docs.helpmanual.io/
참고 블로그 : https://wookkl.tistory.com/62
FastAPI는 기존의 flask, django와 다르게, Pydantic
라이브러리를 사용해서 Data Validation을 하므로 파라미터 값에 어떤 자료형이 들어와야 하는지 코드상에 명시
하고, invalid data라면 에러를 제공한다.
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name = 'John Doe'
signup_ts: Optional[datetime] = None
friends: List[int] = []
external_data = {
'id': '123',
'signup_ts': '2019-06-01 12:22',
'friends': [1, 2, '3'],
}
user = User(**external_data)
print(user.id)
#> 123
print(repr(user.signup_ts))
#> datetime.datetime(2019, 6, 1, 12, 22)
print(user.friends)
#> [1, 2, 3]
print(user.dict())
"""
{
'id': 123,
'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
'friends': [1, 2, 3],
'name': 'John Doe',
}
"""
타입으로만 정의하면 pydantic은 이 필드가 required filed라고 설정한다. str, float, byte 이 input으로 들어오면 int 형으로 바꾸고, 안된다면 Exception 에러를 일으킨다.
id
필드와 다르게 'John Doe'라는 default 값을 지정해주었으므로 required fields는 아니다.
datetime 필드로 지정되고 None이 주어졌으므로 required fields는 아니다.
id
필드와 같이, List 안에 Integer-like 원소가 있으면 Int형으로 바꿔준다.
Invalid한 데이터일 경우 아래와 같이 알려준다.
from pydantic import ValidationError
try:
User(signup_ts='broken', friends=[1, 2, 'not number'])
except ValidationError as e:
print(e.json())
[
{
"loc": [
"id"
],
"msg": "field required",
"type": "value_error.missing"
},
{
"loc": [
"signup_ts"
],
"msg": "invalid datetime format",
"type": "value_error.datetime"
},
{
"loc": [
"friends",
2
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
표준 파이썬 타입으로 파라미터, body 등을 정의 할 수 있기 때문에 새로운 문법이나 특정 라이브러리 사용방법 등을 배울 필요가 없다.
item_id
에 대한 GET
, PUT
요청을 Validateitem_id
에 대한 GET
, PUT
요청이 int
타입인지 ValitdateGET
요청일 때, q
라는 Optional한 쿼리 파라미터가 있는지 확인q
파라미터가 None
으로 정의디어 있다면 이것은 필수 필드는 아니다.None
이 아니라면 이것은 required fields 이다. /items/{item_id}
과 같은 PUT
요청일 때는 body를 JSON 형식으로 읽음name
이 str
타입인지 확인price
가 float
타입인지 확인is_offer
가 만약 존재한다면 bool
타입이다.