在前面我們透過 Strawberry 將 GraphQL 一些最基礎的概念練習一遍了(https://graphql.org/learn/ 上,最佳實踐以外的內容在這視為最基礎),在這次的內容中,主要是說明一些跟 Strawberry 有關的其他功能,其中有一大部分是跟 Python 的型態標註相關的處理方式。
首先,先說明 Schema 的設定,在之前使用查詢(Query)、變更(Mutation)、指令(Directive)時,最後的步驟就是將它們設定進 Schema 中,除了上述可以設定的引數之外,還有下面這些。
功能有點類似查詢,它是查詢(Query)、變更(Mutation)之外的第三個操作(Operations),主要用於即時資料更新(客戶端收到低延遲的新資料),在之後的內容會再介紹。
可以透過使用 config 來影響 Schema 產生的結果,目前預設的 config 可以修改的屬性很少,主要有兩個,一個是auto_camel_case
,它是用來修改 Schema 的命名方式是否使用駝峰式命名,另一個 Relay 格式單一分頁資料數量限制,Relay 也是之後會再介紹。
auto_camel_case
預設值是True
,代表 Schema 預設用駝峰式命名,下面我們試著使用修改 config:
# app/__init__.py
# ... 省略
+from strawberry.schema.config import StrawberryConfig
# ... 省略
schema = strawberry.Schema(
query=query.Query,
mutation=mutation.Mutation,
directives=[sensitive_text, replace],
+ config=StrawberryConfig(auto_camel_case=False),
)
將auto_camel_case
設為False
,這樣產出的 Schema 就會顯示蛇形命名(Snake Case)。
大部分情況還是推薦使用駝峰式命名,因為大部分的客戶端使用的程式語言(網頁、iOS、Android)都是使用這種命名規則,這樣有助於客戶端將 JSON 格式資料轉換成物件使用。
可以透過加入擴充功能來改變 GraphQL 的執行流程,再後面的內容會再說明如何使用 extensions 來提升 GraphQL 執行上的安全性與執行過程的追蹤。
在某些情況下,產生 Schema 的過程中會有無法辨識到的型態,這個時候就要另外將這些型態加進這個設定內,下面我們嘗試一個範例:
我們要先將auto_camel_case
改成True
# app/types.py
# ... 省略
@strawberry.type
class User:
# ... 省略
- detail: typing.Annotated[
- typing.Union[
- NormalUserDetail,
- StaffUserDetail,
- ManagerUserDetail,
- AdminUserDetail,
- ],
- strawberry.union("UserDetail"),
- ]
+ detail: UserProfile
我將使用者詳細資訊欄位的型態改成標記UserProfile
這個介面型態,會在執行時出現錯誤,且在旁邊的資訊可以看到沒有任何實作的型態(Implementations)。
接著把實作的型態加到 types 的設定中。
# app/__init__.py
# ... 省略
-from app import query, mutation
+from app import query, mutation, types
# ... 省略
schema = strawberry.Schema(
query=query.Query,
mutation=mutation.Mutation,
directives=[sensitive_text, replace],
config=StrawberryConfig(auto_camel_case=True),
+ types=[
+ types.NormalUserDetail,
+ types.StaffUserDetail,
+ types.ManagerUserDetail,
+ ],
)
到這邊就可以正常執行了,左邊也可以看到這個介面有哪些實作的型態。
另外上面的範例是沒有AdminUserDetail
這個型態的資料的前提下,才能正常執行。
這是將純量型態進行覆寫的設定,下面用一個簡單的範例來展示:
# app/types.py
# ... 省略
+TWDate = strawberry.scalar(
+ datetime.date,
+ serialize=lambda date: date.strftime("%Y年%m月%d日"),
+ parse_value=lambda date: datetime.datetime.strptime(date, "%Y年%m月%d日").date(),
+ description="Taiwan date",
+)
# app/__init__.py
# ... 省略
schema = strawberry.Schema(
query=query.Query,
mutation=mutation.Mutation,
directives=[sensitive_text, replace],
config=StrawberryConfig(auto_camel_case=True),
types=[
types.NormalUserDetail,
types.StaffUserDetail,
types.ManagerUserDetail,
],
+ scalar_overrides={
+ datetime.date: types.TWDate,
+ },
)
strawberry 支援 Python 3的 Generic 的型態標註,泛型是讓我們建立通用型別的手段,所謂的通用型別指的是,我們將一個類別當作是容器,而泛型的用途就是用來定義容器內容物的型態的參數,通用型別可以同ㄧ個類別重複使用,下面是 strawberry 官方文件上示範的分頁泛型型態:
from typing import Generic, List, TypeVar
import strawberry
T = TypeVar("T")
@strawberry.type
class Page(Generic[T]):
number: int
items: List[T]
其中T
就是讓我們填入不同型態的泛型,例如我們要回傳分頁的使用者列表,我就可以Page[User]
這樣標註型態。
在 Python 中多個模組互相匯入使用,時常會遇到循環匯入(Circular Imports)的問題,strawberry 提供惰性型別的方式,解決在型態標註時循環匯入問題,惰性型別需要搭配TYPE_CHECKING
與Annotated
使用,這邊也是以官方範例做說明:
from typing import TYPE_CHECKING, Annotated
import strawberry
if TYPE_CHECKING:
from .users import User
@strawberry.type
class Post:
title: str
author: Annotated["User", strawberry.lazy(".users")]
上面的範例,前面的TYPE_CHECKING
判斷式內的區塊匯入了只在型別檢查才會用到的模組,在下面的author
屬性中標註型態使用者型態,strawberry.lazy 的引數是模組的路徑字串,用來在型別檢查以外需要解析型態時能正常找到該型態的手段。
在建立 strawberry.type 的類別時會發現,裡面定義的屬性會變成 GraphQL 的欄位,但是如果我們有些屬性不想出現在 GraphQL,私有欄位就是 strawberry 提供給我們做到這麼需求的功能,使用方法就是在型態標註用strawberry.Private
包裹對應的型別,範例如下:
@strawberry.type
class Post:
title: str
author: User
creator: strawberry.Private[User]
Strawberry GraphQL Playground 是 Strawberry 官方提供線上服務,這個服務可以讓我們不必建立開發環境的清況下有個簡易且快速練習與測試 GraphQL 的介面環境。
相關完整程式碼修改紀錄:
到這邊,關於 strawberry 的使用教學就到一個段落了,之後將使用 Django 與 strawberry 整合,來實作 GraphQL API,並且進一步介紹更多的 GraphQL 功能。