文章目錄
什麼是 FastAPI?
FastAPI 提供了方便快速開發的環境,透過自動產生文件與支援型別確認減少錯誤,官方文件表示能夠減少大約 40% 的人為錯誤。
- Type Hint 支援,增加程式可讀性,檢查變數型態更方便
- 符合 OpenAPI,能產生配置檔提供相關工具使用
- 透過服務自動生成線上文件
- API Spec 文件管理困難: 以往開發者還需要去撰寫像是 swagger.json 去產生線上文件
- 解決 Python GIL 限制,可以跑 ASGI
- WSGI: 同步溝通
- ASGI: 非同步溝通
怎麼使用 FastAPI?
沒有最好的工具,只有適合的工具,小編在這邊體驗過後,推薦給大家 :)
簡單撰寫並啟動後,除了程式定義的路徑外還會自動生成文件及設定檔:
- 自動產生可互動的線上文件
/docs
產生 swagger 文件頁面,可以執行 live demo/redoc
產生 ReDoc 文件頁面,可以執行 live demo
/openapi.json
可以拿去其他任何支援 openapi 的工具和平台利用- 譬如生成一個 Mock Server 幫助開發
- 安裝
pip install fastapi uvicorn
- 建立一個範例檔
demo.py
from fastapi import FastAPI
app = FastAPI()
@app.get('/book/{book_id}')
def get_book_by_id(book_id: int):
return {
'book_id': book_id
}
- 執行
uvicorn demo:app --reload
到可以線上互動的文件去觀察目前的情況:
Swagger:
/docs
(圖片來源: https://fastapi.tiangolo.com/)
ReDoc:
/redoc
(圖片來源: https://fastapi.tiangolo.com/)
Path Param
可以定義同樣的路徑,一個用變數一個用定值,路由的比對是照順序,所以要確認 /users/me
放在前面
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
Query Param
/get_book?book_id=132
- 用 query param 的方式帶參數
@app.get('/get_book')
def get_book_by_id_via_query(book_id: int):
return {
'book_id': book_id
}
/book/1/with_mode?query_mode=author
- 嘗試混和 url path 跟 query param
- 定義
query_mode
的選項只有author
、customer
兩種
class QueryModeEnum(Enum):
AUTHOR = 'author'
CUSTOMER = 'customer'
@app.get('/book/{book_id}/with_mode')
def get_book_by_id_mix(book_id: int, query_mode: QueryModeEnum):
return {
'book_id': book_id,
'query_mode': query_mode,
}
Input Validation
/book/{book_id}/with_validation
- 幫網址列的輸入參數加上防呆,這裡的例子為要大於 1
- 定義 Book 物件格式
- 可以放在 Input 的參數中防呆
from fastapi import Path
from pydantic import BaseModel, Field
class Book(BaseModel):
bid: int = Field(..., ge=1, title='book id', description='`markdown`', example=5)
name: str = Field(..., min_length=2)
price: float = Field(..., gt=0)
category: BookCategory
@app.get('/book/{book_id}/with_validation')
def get_book_by_id_with_validation(book_id: int = Path(..., ge=1)):
return {
'book_id': book_id
}
@app.post('/book', response_model=Book)
def get_book_by_id_with_validation_and_some_extra_documnet(
payload: Book
):
payload.name += ' suffix'
return payload
Response Validation
- 定義 BookCategory 的列舉,可以限定 category 只能二擇一
- 定義 Book 物件格式
- 決定回傳的格式參數,若是亂傳就會失敗
from pydantic import BaseModel, Field
class BookCategory(str, Enum):
comics = 'comics'
cooking = 'cooking'
class Book(BaseModel):
bid: int = Field(..., ge=1, title='book id', description='`markdown`', example=5)
name: str = Field(..., min_length=2)
price: float = Field(..., gt=0)
category: BookCategory
@app.get('/book/{book_id}/with_response_model', response_model=Book)
def get_book_by_id_with_validation_and_some_extra_documnet(
book_id: int = Path(..., ge=1, example=5)
):
return {'book_id': book_id}
# return {
# "bid": 5,
# "name": "string suffix",
# "price": 10,
# "category": "comics"
# }
喜歡這篇文章,請幫忙拍拍手喔 🤣