上一篇以自己的万能 BFF 项目为例,聊了一下什么是 GraphQL 以及如何使用 NestJs 框架来开发 GraphQL API ,比较干。今天聊一聊湿一点的内容,GraphQL API 的设计。GraphQL API 的设计原则和 restful API 的设计原则还挺不一样,关于 Restful API 的设计,详见该专栏的讨论:
首先强调一下我个人认为的最重要的两条指导原则,然后在这两条最重要的原则的指导下,引申阐述设计细节。向后兼容老版本这是我认为最重要的一条,但是在实际的团队开发中,却总是有成员违反的一条。总是有人尝试带来破坏性的改动,而且在代码审核环节被提出有兼容问题的时候,总是以前后端一起发版,没有问题来反驳。实际上,完全的同时发版,不仅做不到,更加不是一个好的实践。好的实践是不同的服务和不同的微前端,各自可以随时独立发版,不要有依赖顺序。如果做到这一点很难,那么,允许前端在服务发版之后再行发版,是必须要做到的,不能再妥协了。而且,就算同时发布,有些前端程序要推送到所有设备是有一个时间延迟的。比如微信小程序前端的更新,要100%完成,是需要最长24小时的。也就是说,最长24小时的时间里,会同时存在新老两个版本。如果 GraphQL API 不能兼容老版本,就会有用户在这段时间里碰到问题。因此,原则是已有的查询无论如何不能被破坏。推论一:一旦一个字段被发布到了线上,就不能被删除了。如果真的需要删除它,那么,先将该字段标记为已废弃。当确保所有的前端都已经相应地更新完毕,再进行安全删除。在敏捷开发中,建议至少在前端修改上线后的下一个迭代周期里进行字段的删除修改。推论二:和推论一一样,一旦一个字段发布到了线上,就不能重命名了。实在需要重命名,那么请先新建一个字段,同时将旧字段标记为已废弃。确保所有前端对旧字段的引用改成使用新字段后,再对旧字段进行安全删除。向前考虑扩展性对所有的查询和操作,总是使用自定义对象类型(无论是输入参数还是响应负载都应如此)。否则,你就移除了未来向已有的查询和操作添加其他返回类型及元数据的可能性。而在设计无版本的 GraphQL API 中,提前压缩设计空间绝对不是你真正想做的。并且,原始类型迷恋也是一种代码坏味道(https://refactoring.guru/smells/primitive-obsession)。