Query
字段、变量与片段。
30 分钟
Query
这一课你将能做到
- 写出带参数、变量、别名、指令的完整查询,为「课时详情页」一次取齐数据
- 用片段(Fragment)消除重复字段集,并理解内联片段在多态类型上的用法
- 解释操作名(Operation Name)在生产环境为什么不是可选项
为什么要学
Query 是 GraphQL 里你 90% 时间在与它打交道的东西。上一课的类型系统是「服务端能提供什么」,这一课是「客户端怎么精确地要」。别名解决字段冲突,变量解决动态参数,片段解决重复,指令解决条件渲染——四件套配齐,真实业务的查询都能优雅写出来。
人话:SQL 的 SELECT 语句决定列,GraphQL 的 Query 决定「图的哪棵子树」。
先建立图像
一次课时详情页查询的解剖图:
query LessonPage($slug: String!, $withProgress: Boolean!) { ← 操作名 + 变量声明
lesson(slug: $slug) { ← 字段 + 参数
...LessonCore ← 片段展开
author { name } ← 嵌套字段(图遍历)
progress: myProgress @include(if: $withProgress) { ← 别名 + 指令
status
percent
}
}
}
执行顺序:解析变量 → 校验(对 Schema)→ 逐层执行 resolver → 拼装成镜像 JSON。
跟着做
步骤 1:最小查询到带参查询
# 最小:匿名查询
{ lessons(first: 5) { title slug } }
# 带参数:参数直接写在字段后
{ lesson(slug: "gqlrm-queries") { title durationMinutes } }
注意第一行是匿名查询——只能有一个,且生产环境禁用(见要点 5)。
步骤 2:变量——把动态值踢出查询字符串
永远不要字符串拼接查询。声明变量,值放在请求体的 variables 里:
query LessonDetail($slug: String!, $first: Int = 10) {
lesson(slug: $slug) {
title
submissions(first: $first) { id status }
}
}
// 请求体
{
"query": "query LessonDetail(...) {...}",
"variables": { "slug": "gqlrm-queries" },
"operationName": "LessonDetail"
}
变量类型声明里的 ! 表示必传;= 10 是默认值。变量是类型安全的:传了 Int 给 String!,校验直接拒绝。
步骤 3:别名——同一个字段查两次
对比两种难度的课时,同名字段必须用别名区分:
query CompareLessons {
easy: lesson(slug: "gqlrm-intro") { title difficulty }
hard: lesson(slug: "gqlrm-auth") { title difficulty }
}
返回的 key 就是别名:{ "data": { "easy": {...}, "hard": {...} } }。
步骤 4:片段——DRY 你的字段集
列表卡片和详情头部都要「标题 + slug + 难度 + 时长」,抽成片段:
fragment LessonCard on Lesson {
title
slug
difficulty
durationMinutes
}
query TrackPage($slug: String!) {
track(slug: $slug) {
title
lessons { ...LessonCard }
}
}
query Related($slug: String!) {
lesson(slug: $slug) {
...LessonCard
track { lessons { ...LessonCard } }
}
}