skillhub-095-graphql-operations
441 行
6.3 KiB
Markdown
441 行
6.3 KiB
Markdown
# GraphQL 变量模式
|
||
|
||
本参考文档涵盖在 GraphQL 操作中使用变量的模式。
|
||
|
||
## 目录
|
||
|
||
- [变量基础](#variable-basics)
|
||
- [变量类型](#variable-types)
|
||
- [默认值](#default-values)
|
||
- [复杂输入](#complex-inputs)
|
||
- [最佳实践](#best-practices)
|
||
|
||
## 变量基础
|
||
|
||
### 声明变量
|
||
|
||
变量在操作定义中声明:
|
||
|
||
```graphql
|
||
query GetUser($id: ID!) {
|
||
user(id: $id) {
|
||
id
|
||
name
|
||
}
|
||
}
|
||
```
|
||
|
||
### 使用变量
|
||
|
||
变量以 `$` 前缀引用:
|
||
|
||
```graphql
|
||
query GetUser($id: ID!) {
|
||
user(id: $id) {
|
||
# 此处使用 $id
|
||
id
|
||
name
|
||
}
|
||
}
|
||
```
|
||
|
||
### 传递变量
|
||
|
||
变量以独立的 JSON 对象形式传递:
|
||
|
||
```typescript
|
||
const { data } = await client.query({
|
||
query: GET_USER,
|
||
variables: {
|
||
id: "user_123",
|
||
},
|
||
});
|
||
```
|
||
|
||
### 多个变量
|
||
|
||
```graphql
|
||
query SearchPosts($query: String!, $status: PostStatus, $first: Int!, $after: String) {
|
||
searchPosts(query: $query, status: $status, first: $first, after: $after) {
|
||
edges {
|
||
node {
|
||
id
|
||
title
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"query": "graphql",
|
||
"status": "PUBLISHED",
|
||
"first": 10,
|
||
"after": "cursor_abc"
|
||
}
|
||
```
|
||
|
||
## 变量类型
|
||
|
||
### 标量类型
|
||
|
||
```graphql
|
||
query Example(
|
||
$id: ID!
|
||
$name: String!
|
||
$count: Int!
|
||
$price: Float!
|
||
$active: Boolean!
|
||
) {
|
||
# ...
|
||
}
|
||
```
|
||
|
||
### 自定义标量类型
|
||
|
||
```graphql
|
||
query Example(
|
||
$date: DateTime!
|
||
$email: Email!
|
||
$url: URL!
|
||
) {
|
||
# ...
|
||
}
|
||
```
|
||
|
||
### 枚举类型
|
||
|
||
```graphql
|
||
query GetPosts($status: PostStatus!) {
|
||
posts(status: $status) {
|
||
id
|
||
title
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"status": "PUBLISHED"
|
||
}
|
||
```
|
||
|
||
### 列表类型
|
||
|
||
```graphql
|
||
query GetUsers($ids: [ID!]!) {
|
||
users(ids: $ids) {
|
||
id
|
||
name
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"ids": ["user_1", "user_2", "user_3"]
|
||
}
|
||
```
|
||
|
||
### 输入对象类型
|
||
|
||
```graphql
|
||
mutation CreatePost($input: CreatePostInput!) {
|
||
createPost(input: $input) {
|
||
id
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"input": {
|
||
"title": "My Post",
|
||
"content": "Post content...",
|
||
"tags": ["graphql", "api"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 必需 vs 可选
|
||
|
||
```graphql
|
||
query Example(
|
||
$required: String! # 必须提供,不能为 null
|
||
$optional: String # 可以省略或为 null
|
||
$requiredList: [String!]! # 列表必填,元素必填
|
||
$optionalList: [String] # 列表可选,元素可选
|
||
) {
|
||
# ...
|
||
}
|
||
```
|
||
|
||
## 默认值
|
||
|
||
### 简单默认值
|
||
|
||
```graphql
|
||
query GetPosts($first: Int = 10, $status: PostStatus = PUBLISHED) {
|
||
posts(first: $first, status: $status) {
|
||
id
|
||
title
|
||
}
|
||
}
|
||
```
|
||
|
||
如果未提供,则使用默认值:
|
||
|
||
```json
|
||
{}
|
||
// 等效于:{ "first": 10, "status": "PUBLISHED" }
|
||
```
|
||
|
||
覆盖默认值:
|
||
|
||
```json
|
||
{
|
||
"first": 20
|
||
}
|
||
// 使用 first: 20,status: PUBLISHED(默认值)
|
||
```
|
||
|
||
### 可选变量的默认值
|
||
|
||
```graphql
|
||
# 变量为可选(无 !),但有默认值
|
||
query GetPosts($first: Int = 10) {
|
||
posts(first: $first) {
|
||
id
|
||
}
|
||
}
|
||
```
|
||
|
||
### 复杂类型的默认值
|
||
|
||
```graphql
|
||
query GetPosts($orderBy: PostOrderInput = { field: CREATED_AT, direction: DESC }) {
|
||
posts(orderBy: $orderBy) {
|
||
id
|
||
title
|
||
}
|
||
}
|
||
```
|
||
|
||
### 何时使用默认值
|
||
|
||
在以下场景使用默认值:
|
||
|
||
- 分页限制(`first: Int = 20`)
|
||
- 排序顺序(`direction: SortDirection = DESC`)
|
||
- 常见筛选值(`status: Status = ACTIVE`)
|
||
- 功能开关(`includeArchived: Boolean = false`)
|
||
|
||
## 复杂输入
|
||
|
||
### 嵌套输入对象
|
||
|
||
```graphql
|
||
mutation CreateOrder($input: CreateOrderInput!) {
|
||
createOrder(input: $input) {
|
||
id
|
||
total
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"input": {
|
||
"customer": {
|
||
"email": "customer@example.com",
|
||
"name": "John Doe"
|
||
},
|
||
"items": [
|
||
{ "productId": "prod_1", "quantity": 2 },
|
||
{ "productId": "prod_2", "quantity": 1 }
|
||
],
|
||
"shippingAddress": {
|
||
"street": "123 Main St",
|
||
"city": "New York",
|
||
"state": "NY",
|
||
"zipCode": "10001",
|
||
"country": "US"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 输入对象列表
|
||
|
||
```graphql
|
||
mutation BulkCreateUsers($inputs: [CreateUserInput!]!) {
|
||
bulkCreateUsers(inputs: $inputs) {
|
||
id
|
||
email
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"inputs": [
|
||
{ "email": "user1@example.com", "name": "User 1" },
|
||
{ "email": "user2@example.com", "name": "User 2" },
|
||
{ "email": "user3@example.com", "name": "User 3" }
|
||
]
|
||
}
|
||
```
|
||
|
||
### 筛选输入
|
||
|
||
```graphql
|
||
query SearchProducts($filter: ProductFilter!) {
|
||
products(filter: $filter) {
|
||
id
|
||
name
|
||
price
|
||
}
|
||
}
|
||
```
|
||
|
||
```json
|
||
{
|
||
"filter": {
|
||
"category": "ELECTRONICS",
|
||
"priceRange": {
|
||
"min": 100,
|
||
"max": 500
|
||
},
|
||
"inStock": true,
|
||
"tags": ["featured", "sale"]
|
||
}
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 始终对动态值使用变量
|
||
|
||
```graphql
|
||
# 好:使用变量
|
||
query GetUser($id: ID!) {
|
||
user(id: $id) {
|
||
id
|
||
name
|
||
}
|
||
}
|
||
|
||
# 差:硬编码值
|
||
query GetUser {
|
||
user(id: "123") {
|
||
id
|
||
name
|
||
}
|
||
}
|
||
```
|
||
|
||
### 变量名与参数名保持一致
|
||
|
||
```graphql
|
||
# 好:关系清晰
|
||
query GetUser($userId: ID!) {
|
||
user(id: $userId) {
|
||
id
|
||
}
|
||
}
|
||
|
||
# 也不错:同名
|
||
query GetUser($id: ID!) {
|
||
user(id: $id) {
|
||
id
|
||
}
|
||
}
|
||
|
||
# 差:命名混乱
|
||
query GetUser($x: ID!) {
|
||
user(id: $x) {
|
||
id
|
||
}
|
||
}
|
||
```
|
||
|
||
### 使用描述性变量名
|
||
|
||
```graphql
|
||
# 好
|
||
query SearchPosts(
|
||
$searchQuery: String!
|
||
$authorId: ID
|
||
$publishedAfter: DateTime
|
||
$maxResults: Int = 20
|
||
) {
|
||
searchPosts(
|
||
query: $searchQuery
|
||
author: $authorId
|
||
after: $publishedAfter
|
||
first: $maxResults
|
||
) {
|
||
# ...
|
||
}
|
||
}
|
||
|
||
# 差
|
||
query SearchPosts($q: String!, $a: ID, $d: DateTime, $n: Int) {
|
||
# ...
|
||
}
|
||
```
|
||
|
||
### 对相关变量进行分组
|
||
|
||
```typescript
|
||
// 好:variables 对象反映输入结构
|
||
const variables = {
|
||
input: {
|
||
title: formData.title,
|
||
content: formData.content,
|
||
tags: formData.tags,
|
||
},
|
||
};
|
||
|
||
// 不够清晰:扁平变量
|
||
const variables = {
|
||
title: formData.title,
|
||
content: formData.content,
|
||
tags: formData.tags,
|
||
};
|
||
```
|
||
|
||
### 在客户端校验变量
|
||
|
||
```typescript
|
||
function createPost(input: CreatePostInput) {
|
||
// 发送前校验
|
||
if (!input.title?.trim()) {
|
||
throw new Error("Title is required");
|
||
}
|
||
if (input.title.length > 200) {
|
||
throw new Error("Title too long");
|
||
}
|
||
|
||
return client.mutate({
|
||
mutation: CREATE_POST,
|
||
variables: { input },
|
||
});
|
||
}
|
||
```
|
||
|
||
### 使用 TypeScript 为变量提供类型
|
||
|
||
```typescript
|
||
// 从 schema 生成的类型
|
||
interface GetUserQueryVariables {
|
||
id: string;
|
||
}
|
||
|
||
// 配合 Apollo Client 使用
|
||
const { data } = useQuery<GetUserQuery, GetUserQueryVariables>(GET_USER, {
|
||
variables: { id: userId }, // 类型已检查
|
||
});
|
||
```
|