什麼是 FastAPI?
FastAPI 提供了方便快速開發的環境,透過自動產生文件與支援型別確認減少錯誤,官方文件表示能夠減少大約 40% 的人為錯誤。
- Type Hint 支援,增加程式可讀性,檢查變數型態更方便
- 符合 OpenAPI,能產生配置檔提供相關工具使用
- 透過服務自動生成線上文件
- API Spec 文件管理困難: 以往開發者還需要去撰寫像是 swagger.json 去產生線上文件
- 解決 Python GIL 限制,可以跑 ASGI
怎麼使用 FastAPI?
沒有最好的工具,只有適合的工具,小編在這邊體驗過後,推薦給大家 :)
簡單撰寫並啟動後,除了程式定義的路徑外還會自動生成文件及設定檔:
- 自動產生可互動的線上文件
/docs
產生 swagger 文件頁面,可以執行 live demo/redoc
產生 ReDoc 文件頁面,可以執行 live demo
/openapi.json
可以拿去其他任何支援 openapi 的工具和平台利用
- 安裝
1
| pip install fastapi uvicorn
|
- 建立一個範例檔
demo.py
1 2 3 4 5 6 7 8
| from fastapi import FastAPI app = FastAPI()
@app.get('/book/{book_id}') def get_book_by_id(book_id: int): return { 'book_id': book_id }
|
- 執行
1
| uvicorn demo:app --reload
|
到可以線上互動的文件去觀察目前的情況:
Swagger: /docs
(圖片來源: https://fastapi.tiangolo.com/)
ReDoc: /redoc
(圖片來源: https://fastapi.tiangolo.com/)
Path Param
可以定義同樣的路徑,一個用變數一個用定值,路由的比對是照順序,所以要確認 /users/me
放在前面
1 2 3 4 5 6 7 8
| @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
1 2 3 4 5
| @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
兩種
1 2 3 4 5 6 7 8 9 10
| 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, }
|
/book/{book_id}/with_validation
- 幫網址列的輸入參數加上防呆,這裡的例子為要大於 1
- 定義 Book 物件格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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 物件格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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}
|
喜歡這篇文章,請幫忙拍拍手喔 🤣