在學習如何查詢之前,我們應該先要有一些資料,為此我們建立一個服務元件來產生假資料。
首先安裝一個產生假資料的 Python 套件,faker
:
$ poetry add 'faker==19.6.0'
接著建立一個UserService
來作為操作使用者資料的服務。
# app/services.py
import typing
from faker import Faker
from app import types
fake = Faker(["zh_TW", "en_US"])
def gen_user_info() -> (
typing.Tuple[
typing.Dict[str, typing.Any],
typing.Dict[str, typing.Any],
]
):
profile = fake.simple_profile()
user_info = dict(
id=fake.random_int(min=1),
username=profile["username"],
email=fake.ascii_safe_email(),
first_name=fake.first_name(),
last_name=fake.last_name(),
password=fake.lexify(text="??????????????????????????????"),
last_login=fake.date_time_this_century() if fake.random_digit() > 1 else None,
is_active=bool(fake.random_digit() > 1),
)
detail = dict(
birthdate=profile["birthdate"],
address=profile["address"],
phone=fake.phone_number(),
)
return user_info, detail
def gen_normal_user() -> types.User:
user_info, detail = gen_user_info()
user_info["role"] = types.UserRole.NORMAL
user_info["detail"] = types.NormalUserDetail(**detail)
return types.User(**user_info)
def gen_staff_user(department: str) -> types.User:
user_info, detail = gen_user_info()
user_info["role"] = types.UserRole.STAFF
detail["department"] = department
user_info["detail"] = types.StaffUserDetail(**detail)
return types.User(**user_info)
def gen_manager_user(
department: str,
subordinates: typing.List[types.User],
) -> types.User:
user_info, detail = gen_user_info()
user_info["role"] = types.UserRole.MANAGER
detail["department"] = department
detail["subordinates"] = subordinates
user_info["detail"] = types.ManagerUserDetail(**detail)
return types.User(**user_info)
def gen_admin_user() -> types.User:
user_info, _ = gen_user_info()
user_info["role"] = types.UserRole.ADMIN
user_info["detail"] = types.AdminUserDetail(
system_permissions=fake.random_choices(
elements=(
"read_users",
"read_user",
"write_user",
"update_user",
"delete_user",
),
)
)
return types.User(**user_info)
class UserService:
def __init__(self) -> None:
self.normal_users = [gen_normal_user() for _ in range(20)]
self.staff_users = []
self.manager_users = []
self.admin_users = [gen_admin_user() for _ in range(10)]
self.departments = [
"Human Resources",
"IT",
"Accounting",
"Finance",
"Marketing",
"Research",
"Development",
"Production",
]
self._gen_department_users()
def _gen_department_users(self) -> None:
for department in fake.random_choices(elements=self.departments):
staffs = [gen_staff_user(department) for _ in range(fake.random_digit())]
managers = [
gen_manager_user(department, staffs)
for _ in range(fake.random_int(min=0, max=5))
]
self.staff_users.extend(staffs)
self.manager_users.extend(managers)
def all_users(self) -> typing.List[types.User]:
return list(
self.normal_users + self.admin_users + self.staff_users + self.manager_users
)
def user(self, id: int) -> typing.Optional[types.User]:
for user in self.all_users():
if user.id == id:
return user
return None
fake = Faker(["zh_TW", "en_US"])
:建立一個fake
物件,Faker
傳入一個要產生哪些語系的假資料列表。gen_user_info()
:產生使用者基本資料與詳細資訊的共通欄位。gen_normal_user()
:產生普通使用者物件。gen_staff_user(department)
:產生特定部門員工物件。gen_manager_user(department, subordinates)
:產生特定部門與所屬下屬管理者物件。gen_admin_user()
:產生系統管理者物件。UserService.__init__()
:初始化,產生所有類型使用者物件列表。UserService._gen_department_users()
:產生有部門的使用者物件列表。UserService.all_users()
:列出所有類型使用者物件列表。UserService.user(id)
:使用 id 查詢特定使用者。接者將UserService
跟 GraphQL 查詢物件串接在一起。
# app/query.py
import typing
-import datetime
import strawberry
-from app import types
+from app import types, services
+user_service = services.UserService()
-def get_users() -> typing.List[types.User]:
- return [
- types.User(
- id=1,
- username="bob",
- email="bob@mymail.com",
- first_name="Bob",
- last_name="User",
- password="xxxxxx",
- last_login=datetime.datetime.now(),
- role=types.UserRole.NORMAL,
- ),
- ]
@strawberry.type
class Query:
- users: typing.List[types.User] = strawberry.field(resolver=get_users)
+ users: typing.List[types.User] = strawberry.field(resolver=user_service.all_users)
+ user: typing.Optional[types.User] = strawberry.field(resolver=user_service.user)
這邊新增了兩個查詢物件,分別是列出所有使用者(users
)與查詢某個使用者(user
)。
到這邊我們可以在 GraphiQL 的頁面上使用 GraphiQL Explorer,使用點選的方式建立查詢,或是直接編輯查詢語法。
query UserListQuery {
users {
email
firstName
fullName
id
isActive
lastLogin
lastName
password
role
username
}
}
我們使用查詢語法建立一個名為UserListQuery
的查詢,執行並得到所有使用者的基本資料:
圖上有標記 GraphiQL 頁面 Explorer 操作順序。
query UserQuery {
user(id: 2896) {
username
id
email
isActive
fullName
firstName
lastLogin
lastName
password
role
}
}
我們再建立另一個查詢UserQuery
,來得到特定 id 的使用者資訊:
圖上有標記 GraphiQL 頁面 Explorer 操作順序。
到這邊就完成兩個最基本的查詢操作。
在上面的兩個查詢操作(Queries),我們定義兩個名稱,分別是UserListQuery
與UserQuery
在 GraphQL 中稱為操作名稱(Operation name),而user(id: 2896)
的 id: 稱為引數(Arguments)。
app/query.py
的完整程式碼:
import typing
import strawberry
from app import types, services
user_service = services.UserService()
@strawberry.type
class Query:
users: typing.List[types.User] = strawberry.field(resolver=user_service.all_users)
user: typing.Optional[types.User] = strawberry.field(resolver=user_service.user)