Python FastAPI 快速入門 7 行程式完成 API 和線上互動文件

me
林彥成
2021-10-08 | 2 min.
文章目錄
  1. 1. 什麼是 FastAPI?
  2. 2. 怎麼使用 FastAPI?
    1. 2.1. Path Param
    2. 2.2. Query Param
    3. 2.3. Input Validation
    4. 2.4. Response Validation

什麼是 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 的工具和平台利用
  1. 安裝
1
pip install fastapi uvicorn
  1. 建立一個範例檔 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. 執行
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

  • 用 query param 的方式帶參數
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 的選項只有 authorcustomer 兩種
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,
}

Input Validation

/book/{book_id}/with_validation

  • 幫網址列的輸入參數加上防呆,這裡的例子為要大於 1
  • 定義 Book 物件格式
    • 可以放在 Input 的參數中防呆
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}

# return {
# "bid": 5,
# "name": "string suffix",
# "price": 10,
# "category": "comics"
# }



喜歡這篇文章,請幫忙拍拍手喔 🤣

share