运行时依赖
无特殊依赖
安装命令
点击复制官方npx clawhub@latest install golang-graphql
镜像加速npx clawhub@latest install golang-graphql --registry https://cn.longxiaskill.com 镜像可用
技能文档
作为一名Go GraphQL工程师,您故意设计模式,批量访问数据库以防止N+1,并将查询复杂度限制视为生产环境中的必需项。
模式:
- 构建模式:生成新模式、解析器或服务器设置时,按照技能的顺序指令进行;启动后台代理以grep现有的解析器模式和命名约定,然后生成新代码。
- 审核模式:审核GraphQL代码库或PR时,使用子代理扫描N+1解析器模式、缺失复杂度限制、全局DataLoaders和生产环境中启用的introspection,同时阅读业务逻辑。
- 默认社区。
- Explicitly覆盖samber/cc-skills-golang@golang-graphql技能的公司技能优先。
Go GraphQL最佳实践:
- 两个主要库都是模式优先的:编写SDL(.graphql文件),绑定Go解析器。根据项目大小和团队偏好进行选择。
- 本技能并不详尽。请参考每个库的官方文档和代码示例以获取当前的API签名。
- Context7可以作为发现平台提供帮助。
库选择:
- 库方法类型安全构建步骤最适合
- github.com/99designs/gqlgen Codegen 编译时 go generate 大型模式、联合、严格类型
- github.com/graph-gophers/graphql-go 反射 解析时 无 简单模式、快速迭代
- github.com/graphql-go/graphql 代码优先 运行时 无 避免 -冗长、无SDL
选择gqlgen时:Apollo Federation是必需的,模式很大(100+类型),或团队希望生成存根并且没有反射开销。 选择graph-gophers时:模式很小/中等,构建管道应该保持简单,或需要动态模式。
模式设计:
- Explicit nullability;ID标量用于不透明标识符
- 类型User {
- 不良模式:Int ID泄露实现细节,破坏客户端缓存
- 类型Post {
- Nullability规则:仅当服务器可以始终返回值时,才将字段标记为!。
- 分页:使用Relay cursor连接(Connection/Edge/PageInfo)进行列表字段。
- 避免在大型数据集上使用偏移分页 - 在并发写入下,光标是稳定的。
变异:
- 将结果包装在-envelope类型中,以便客户端在不污染GraphQL错误数组的情况下接收业务错误和部分结果。
- 类型CreateUserPayload {
解析器模式:
- 保持解析器薄 - 将GraphQL输入转换为域调用,将域响应转换为GraphQL输出。
- // 好的 - 解析器委托给服务层
- func (r mutationResolver) CreateUser(ctx context.Context, input model.CreateUserInput) (model.CreateUserPayload, error) {
- // 不良 - 解析器中的SQL,无关注点分离
- func (r queryResolver) User(ctx context.Context, id string) (model.User, error) {
使用每种类型的解析器结构(userResolver,postResolver),而不是一个用于所有字段的单一解析器。
N+1预防(DataLoaders):
- 每个User.posts解析器都会为每个用户触发一个SQL查询 - 对于n个用户,会有O(n)个DB调用。
- DataLoaders通过将每个字段加载合并为一个批量查询来解决这个问题。
- 关键规则:DataLoaders必须在每个请求的HTTP中间件中创建,而不是全局创建。
- 全局DataLoader会在请求之间缓存 - 数据可能过时,可能会发生跨用户数据泄露。
- // 好的 - 请求DataLoader在中间件中
- func DataLoaderMiddleware(db sql.DB, next http.Handler) http.Handler {
- // 不良 - 全局DataLoader在所有请求中共享
- var globalLoader = newPostsByUserIDLoader(context.Background(), db)
在gqlgen中,使用gqlgen.yml中的resolver:true标记批量字段,以强制使用专用的解析器方法。请参阅gqlgen参考文档以获取有关DataLoader的完整信息。
身份验证和授权:
- 两层模型:HTTP中间件 - 提取和验证令牌,将身份存储在context.Context中。
- 模式指令(gqlgen)或解析器检查(graphql-go) - 执行每个字段的授权。
- // HTTP中间件层(两个库)
- func AuthMiddleware(next http.Handler) http.Handler {