先记住这个答案
schema-first 先以 SDL 定义 schema,再实现 resolver,契约先行,利于前后端并行与多方评审;code-first 在代码中定义类型并推断出 schema,schema 与实现单一来源,重构友好。取舍看团队协作边界与 schema 变更频率:跨团队或强契约场合用 schema-first;单团队或快速迭代用 code-first。
- 跨团队协作优先 schema-first,单队快速迭代 code-first
- code-first 保证 schema 单一来源,减少不一致
- 变更管控严格时 schema-first 便于评审
- 工具链依赖编程语言与数据模型,谨慎选择
机制:schema 从哪里来,如何保持一致
schema-first 将 SDL 文件当作事实源,resolver 单独实现。运行时框架解析这份 SDL 构建类型图,字段实现则通过命名绑定。协作中,前后端各自对照 SDL,不会出现类型定义只存在于某一侧。其一致性靠版本控制与评审流程维持,resolver 与 SDL 不匹配时,具体行为因框架而异:可能解析字段时报错,也可能返回空值。因此,需要结合自动化测试和评审流程来保证一致性。
code-first 使用语言自带的定义类型,通过类型安全、注解或推理生成 GraphQL schema。这使得 schema 是实现的可推导产物,任何代码变更都可能改变公开契约。好处是单一来源,改进便;代价是每次重构都必须意识到公开 API 变化,否则会无意破坏客户端。
场景:契约圣典式演进
假设一个多团队协作:前端应用、移动端、后端服务,共 5 个小队。采用 schema-first,放置一个 schema 仓库,重大变更通过 PR 评审,SDL diff 自动检查破坏性变更。新功能先定义 SDL,前端可以 mock 数据开发。后端按 SDL 实现,两界明确。
这种方式流程较重,但通过跨团队评审预期可减少生产事故。另一个小队采用 code-first 原型验证新特性,两周后因快速迭代而受益。最终,模式选择要贴在团队节奏与稳定契约的权衡上。
边界:何时不应坚持某一模式
schema-first 在 schema 频繁演进、工具链不成熟的语言中负担明显。SDL 需要额外工具生成类型,增加构建步骤,且当团队规模小、前后端强耦合时评审成本高,或返工频繁。
code-first 在需要跨团队契约约束时风险高,因为实现者可能无意修改代码,导致生成的SDL变化而破坏下游。若有契约测试与护栏可降低此风险;若无,则应在重要分支上强制 code review 关注 schema 变化。
容易答错的地方
- 忽略语言工具链成熟度
- 以为 schema-first 总是更标准,但有的语言 code-first 生态更成熟,工具链更完善。若语言已有从 ORM 到 GraphQL 的完整集成,code-first 能减少手工重复,而强行手写 SDL 反而增加工作量。
- 将模式直接等同于质量
- 有人认为 schema-first 一定会产生清晰 API,其实若没有评审与设计的投入,任何模式都会乱。重要是定义类型时要有语义与业务考量,否则无论哪种产出的 schema 都差。
面试官还会怎么问?
schema-first 中如何保证 SDL 与实际 resolver 一致?
在字段实际解析时,如果缺少对应的 resolver,部分框架会抛错,也有框架会返回空值,所以并不能依赖运行时自动报错。较好的做法是结合自动化测试,遍历 schema 每个字段确保绑定了 resolver。此外要留意 SDL 合并与命名冲突,进行版本控制。
code-first 模式如何维护公开 API 变更记录?
可从生成的 SDL diff 中获取变更记录,将其纳入 CI。在 PR 中展示 schema 变更,并采用语义化版本。另外,生成 SDL 持久化在仓库中,可以对比历史版本。
混合模式是否可行?
可行。例如用 schema-first 定义共性基础类型,用 code-first 扩展内部团队模块。但要注意最终 schema 的单一来源与构建流程整合,否则易造成误导。很多框架支持两者并用。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。