skillhub-095-graphql-operations
245 行
4.2 KiB
Markdown
245 行
4.2 KiB
Markdown
---
|
|
name: graphql-operations
|
|
description: >
|
|
编写 GraphQL 操作(查询、变更、片段)的最佳实践指南。在以下情况下使用本技能:
|
|
(1) 编写 GraphQL 查询或变更,
|
|
(2) 使用片段组织操作,
|
|
(3) 优化数据获取模式,
|
|
(4) 设置类型生成或代码检查,
|
|
(5) 审查操作效率。
|
|
license: MIT
|
|
compatibility: 任意 GraphQL 客户端(Apollo Client、urql、Relay 等)
|
|
metadata:
|
|
author: apollographql
|
|
version: "1.0.0"
|
|
allowed-tools: Bash(npm:*) Bash(npx:*) Read Write Edit Glob Grep
|
|
---
|
|
|
|
# GraphQL 操作指南
|
|
|
|
本指南涵盖了作为客户端开发者编写 GraphQL 操作(查询、变更、订阅)的最佳实践。编写良好的操作应具备高效、类型安全且易于维护的特点。
|
|
|
|
## 操作基础
|
|
|
|
### 查询结构
|
|
|
|
```graphql
|
|
query GetUser($id: ID!) {
|
|
user(id: $id) {
|
|
id
|
|
name
|
|
email
|
|
}
|
|
}
|
|
```
|
|
|
|
### 变更结构
|
|
|
|
```graphql
|
|
mutation CreatePost($input: CreatePostInput!) {
|
|
createPost(input: $input) {
|
|
id
|
|
title
|
|
createdAt
|
|
}
|
|
}
|
|
```
|
|
|
|
### 订阅结构
|
|
|
|
```graphql
|
|
subscription OnMessageReceived($channelId: ID!) {
|
|
messageReceived(channelId: $channelId) {
|
|
id
|
|
content
|
|
sender {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 快速参考
|
|
|
|
### 操作命名
|
|
|
|
| 模式 | 示例 |
|
|
| ------------ | --------------------------------------------- |
|
|
| 查询 | `GetUser`、`ListPosts`、`SearchProducts` |
|
|
| 变更 | `CreateUser`、`UpdatePost`、`DeleteComment` |
|
|
| 订阅 | `OnMessageReceived`、`OnUserStatusChanged` |
|
|
|
|
### 变量语法
|
|
|
|
```graphql
|
|
# 必填变量
|
|
query GetUser($id: ID!) { ... }
|
|
|
|
# 带默认值的可选变量
|
|
query ListPosts($first: Int = 20) { ... }
|
|
|
|
# 多个变量
|
|
query SearchPosts($query: String!, $status: PostStatus, $first: Int = 10) { ... }
|
|
```
|
|
|
|
### 片段语法
|
|
|
|
```graphql
|
|
# 定义片段
|
|
fragment UserBasicInfo on User {
|
|
id
|
|
name
|
|
avatarUrl
|
|
}
|
|
|
|
# 使用片段
|
|
query GetUser($id: ID!) {
|
|
user(id: $id) {
|
|
...UserBasicInfo
|
|
email
|
|
}
|
|
}
|
|
```
|
|
|
|
### 指令
|
|
|
|
```graphql
|
|
query GetUser($id: ID!, $includeEmail: Boolean!) {
|
|
user(id: $id) {
|
|
id
|
|
name
|
|
email @include(if: $includeEmail)
|
|
}
|
|
}
|
|
|
|
query GetPosts($skipDrafts: Boolean!) {
|
|
posts {
|
|
id
|
|
title
|
|
draft @skip(if: $skipDrafts)
|
|
}
|
|
}
|
|
```
|
|
|
|
## 关键原则
|
|
|
|
### 1. 仅请求所需字段
|
|
|
|
```graphql
|
|
# 良好:指定字段
|
|
query GetUserName($id: ID!) {
|
|
user(id: $id) {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
|
|
# 避免:过度获取
|
|
query GetUser($id: ID!) {
|
|
user(id: $id) {
|
|
id
|
|
name
|
|
email
|
|
bio
|
|
posts {
|
|
id
|
|
title
|
|
content
|
|
comments {
|
|
id
|
|
}
|
|
}
|
|
followers {
|
|
id
|
|
name
|
|
}
|
|
# ... 大量未使用的字段
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. 为所有操作命名
|
|
|
|
```graphql
|
|
# 良好:命名操作
|
|
query GetUserPosts($userId: ID!) {
|
|
user(id: $userId) {
|
|
posts {
|
|
id
|
|
title
|
|
}
|
|
}
|
|
}
|
|
|
|
# 避免:匿名操作
|
|
query {
|
|
user(id: "123") {
|
|
posts {
|
|
id
|
|
title
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. 使用变量,而非内联值
|
|
|
|
```graphql
|
|
# 良好:变量
|
|
query GetUser($id: ID!) {
|
|
user(id: $id) {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
|
|
# 避免:硬编码值
|
|
query {
|
|
user(id: "123") {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. 将片段与组件共存
|
|
|
|
```tsx
|
|
// UserAvatar.tsx
|
|
export const USER_AVATAR_FRAGMENT = gql`
|
|
fragment UserAvatar on User {
|
|
id
|
|
name
|
|
avatarUrl
|
|
}
|
|
`;
|
|
|
|
function UserAvatar({ user }) {
|
|
return <img src={user.avatarUrl} alt={user.name} />;
|
|
}
|
|
```
|
|
|
|
## 参考文件
|
|
|
|
各主题的详细文档:
|
|
|
|
- [查询](references/queries.md) —— 查询模式与优化
|
|
- [变更](references/mutations.md) —— 变更模式与错误处理
|
|
- [片段](references/fragments.md) —— 片段组织与复用
|
|
- [变量](references/variables.md) —— 变量用法与类型
|
|
- [工具链](references/tooling.md) —— 代码生成与代码检查
|
|
|
|
## 基本规则
|
|
|
|
- 始终为你的操作命名(禁止匿名查询/变更)
|
|
- 始终对动态值使用变量
|
|
- 始终只请求你需要的字段
|
|
- 始终为可缓存类型包含 `id` 字段
|
|
- 切勿在操作中硬编码值
|
|
- 切勿在文件间重复选择相同的字段
|
|
- 优先使用片段来复用字段选择
|
|
- 优先将片段与组件共存
|
|
- 使用描述性的操作名称来体现用途
|
|
- 对条件字段使用 `@include`/`@skip`
|