Files
2026-07-13 21:36:20 +08:00

6.3 KiB
Raw Permalink Blame History

GraphQL 变量模式

本参考文档涵盖在 GraphQL 操作中使用变量的模式。

目录

变量基础

声明变量

变量在操作定义中声明:

query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
  }
}

使用变量

变量以 $ 前缀引用:

query GetUser($id: ID!) {
  user(id: $id) {
    # 此处使用 $id
    id
    name
  }
}

传递变量

变量以独立的 JSON 对象形式传递:

const { data } = await client.query({
  query: GET_USER,
  variables: {
    id: "user_123",
  },
});

多个变量

query SearchPosts($query: String!, $status: PostStatus, $first: Int!, $after: String) {
  searchPosts(query: $query, status: $status, first: $first, after: $after) {
    edges {
      node {
        id
        title
      }
    }
  }
}
{
  "query": "graphql",
  "status": "PUBLISHED",
  "first": 10,
  "after": "cursor_abc"
}

变量类型

标量类型

query Example(
  $id: ID!
  $name: String!
  $count: Int!
  $price: Float!
  $active: Boolean!
) {
  # ...
}

自定义标量类型

query Example(
  $date: DateTime!
  $email: Email!
  $url: URL!
) {
  # ...
}

枚举类型

query GetPosts($status: PostStatus!) {
  posts(status: $status) {
    id
    title
  }
}
{
  "status": "PUBLISHED"
}

列表类型

query GetUsers($ids: [ID!]!) {
  users(ids: $ids) {
    id
    name
  }
}
{
  "ids": ["user_1", "user_2", "user_3"]
}

输入对象类型

mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    id
  }
}
{
  "input": {
    "title": "My Post",
    "content": "Post content...",
    "tags": ["graphql", "api"]
  }
}

必需 vs 可选

query Example(
  $required: String!     # 必须提供,不能为 null
  $optional: String      # 可以省略或为 null
  $requiredList: [String!]!  # 列表必填,元素必填
  $optionalList: [String]    # 列表可选,元素可选
) {
  # ...
}

默认值

简单默认值

query GetPosts($first: Int = 10, $status: PostStatus = PUBLISHED) {
  posts(first: $first, status: $status) {
    id
    title
  }
}

如果未提供,则使用默认值:

{}
// 等效于:{ "first": 10, "status": "PUBLISHED" }

覆盖默认值:

{
  "first": 20
}
// 使用 first: 20status: PUBLISHED(默认值)

可选变量的默认值

# 变量为可选(无 !),但有默认值
query GetPosts($first: Int = 10) {
  posts(first: $first) {
    id
  }
}

复杂类型的默认值

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

复杂输入

嵌套输入对象

mutation CreateOrder($input: CreateOrderInput!) {
  createOrder(input: $input) {
    id
    total
  }
}
{
  "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"
    }
  }
}

输入对象列表

mutation BulkCreateUsers($inputs: [CreateUserInput!]!) {
  bulkCreateUsers(inputs: $inputs) {
    id
    email
  }
}
{
  "inputs": [
    { "email": "user1@example.com", "name": "User 1" },
    { "email": "user2@example.com", "name": "User 2" },
    { "email": "user3@example.com", "name": "User 3" }
  ]
}

筛选输入

query SearchProducts($filter: ProductFilter!) {
  products(filter: $filter) {
    id
    name
    price
  }
}
{
  "filter": {
    "category": "ELECTRONICS",
    "priceRange": {
      "min": 100,
      "max": 500
    },
    "inStock": true,
    "tags": ["featured", "sale"]
  }
}

最佳实践

始终对动态值使用变量

# 好:使用变量
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
  }
}

# 差:硬编码值
query GetUser {
  user(id: "123") {
    id
    name
  }
}

变量名与参数名保持一致

# 好:关系清晰
query GetUser($userId: ID!) {
  user(id: $userId) {
    id
  }
}

# 也不错:同名
query GetUser($id: ID!) {
  user(id: $id) {
    id
  }
}

# 差:命名混乱
query GetUser($x: ID!) {
  user(id: $x) {
    id
  }
}

使用描述性变量名

# 好
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) {
  # ...
}

对相关变量进行分组

// 好:variables 对象反映输入结构
const variables = {
  input: {
    title: formData.title,
    content: formData.content,
    tags: formData.tags,
  },
};

// 不够清晰:扁平变量
const variables = {
  title: formData.title,
  content: formData.content,
  tags: formData.tags,
};

在客户端校验变量

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 为变量提供类型

// 从 schema 生成的类型
interface GetUserQueryVariables {
  id: string;
}

// 配合 Apollo Client 使用
const { data } = useQuery<GetUserQuery, GetUserQueryVariables>(GET_USER, {
  variables: { id: userId }, // 类型已检查
});