ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

gqlgen 快速上手指南:用 Go 构建类型安全的 GraphQL 服务器

gqlgen 快速上手指南:用 Go 构建类型安全的 GraphQL 服务器 后端GraphQL代码生成【免费下载链接】gqlgengo generate based graphql server library项目地址https://gitcode.com/gh_mirrors/gq/gqlgen点击查看免费下载gqlgen 是一个基于Schema FirstSchema 优先理念的 Go GraphQL 服务器库你先用 GraphQL Schema Definition LanguageSDL定义 API再让 gqlgen 自动生成类型安全、可直接运行的样板代码从而把精力集中在业务实现上。本文将围绕项目官方文档docs/content/_introduction.md的核心脉络介绍 gqlgen 的设计理念、从零搭建服务器的完整步骤并深入讲解官方 FAQ 中最常见的实战问题如何避免无谓地获取子对象、如何重新映射 ID 类型、如何关闭接口 getter。读完本文你将能独立初始化一个 gqlgen 项目并理解配置驱动gqlgen.yml与代码生成的工作方式。gqlgen 是什么gqlgen当前仓库位于gh_mirrors/gq/gqlgen命令行入口见 main.go是一个「无需折腾」即可构建 GraphQL 服务器的 Go 库其设计建立在三个核心理念之上Schema First 方法你通过 GraphQL Schema Definition Language 定义 API。仓库中几乎每个示例都以.graphqls/.graphql文件描述类型、查询与变更例如 _examples/todo/schema.graphql。类型安全优先你不会在代码里看到map[string]interface{}满天飞。gqlgen 会为每个 GraphQL 类型生成对应的强类型 Go 结构体与方法签名。代码生成Codegengqlgen 生成所有「无聊的胶水代码」让你专注于快速构建应用。go tool gqlgen generate会比对 schema 与你的模型能直接绑定的字段直接绑定绑不上的就生成 resolver 占位等待你填充实现。想与其他 Go GraphQL 实现做横向对比可查阅 docs/content/feature-comparison.md。快速开始4 步跑起第一个 GraphQL 服务器官方文档给出了最短路径下面结合仓库源码说明每一步的具体行为。1. 初始化 Go Modulemkdir example cd example go mod init examplegqlgen 的init命令要求当前目录位于一个 Go Module 内。从 main.go 的源码可以看到init会调用code.ImportPathForDir推导当前目录的 import path并向上查找go.mod如果找不到会直接报错go.mod is missing. Please, do go mod init first。2. 以工具依赖方式引入 gqlgengo get -tool github.com/99designs/gqlgenGo 1.24 之后的-tool参数会把 gqlgen 作为项目的工具依赖记录在go.mod的tool指令中随后即可通过go tool gqlgen调用而无需在 PATH 里安装二进制。若需指定版本用VERSION即可go get -tool github.com/99designs/gqlgenVERSION3. 初始化配置并生成模型go tool gqlgen initinit命令main.go 中的initCmd会做以下几件事生成gqlgen.yml配置文件模板见 init-templates/gqlgen.yml.gotmpl生成初始 schema 文件graph/schema.graphqls模板见 init-templates/schema.graphqls通过api.Generateservergen.New插件生成server.go入口文件若gqlgen.yml/ schema / server 文件已存在会报错拒绝覆盖xxx already exists。初始化后你将得到官方推荐的目录结构├── go.mod ├── go.sum ├── gqlgen.yml # gqlgen 配置控制生成代码的开关 ├── graph │ ├── generated # 仅包含生成运行时的包 │ │ └── generated.go │ ├── model # 所有 GraphQL 模型生成或手写 │ │ └── models_gen.go │ ├── resolver.go # 根 resolver 类型不会被重新生成 │ ├── schema.graphqls # schema 文件可拆分为任意多个 │ └── schema.resolvers.go # schema.graphqls 对应的 resolver 实现 └── server.go # 应用入口可按需定制初始 schema 包含一个经典的 Todo 示例type Todo { id: ID! text: String! done: Boolean! user: User! } type User { id: ID! name: String! } type Query { todos: [Todo!]! } input NewTodo { text: String! userId: String! } type Mutation { createTodo(input: NewTodo!): Todo! }4. 启动服务器go run server.go打开 http://localhost:8080即可在浏览器中执行 GraphQL 查询。先用 mutation 创建一条 todomutation createTodo { createTodo(input: { text: todo, userId: 1 }) { user { id } text done } }再查询它query findTodos { todos { text done user { name } } }实现 resolver代码生成的落点go tool gqlgen init生成时凡是 schema 中无法与已有模型绑定的字段都会生成带panic(fmt.Errorf(not implemented))的 resolver 占位集中在graph/schema.resolvers.gofunc (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) { panic(fmt.Errorf(not implemented)) } func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) { panic(fmt.Errorf(not implemented)) }在graph/resolver.go中声明应用依赖如内存存储、数据库句柄然后填充实现即可type Resolver struct{ todos []*model.Todo }func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) { randNumber, _ : rand.Int(rand.Reader, big.NewInt(100)) todo : model.Todo{ Text: input.Text, ID: fmt.Sprintf(T%d, randNumber), User: model.User{ID: input.UserID, Name: user input.UserID}, } r.todos append(r.todos, todo) return todo, nil } func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) { return r.todos, nil }仓库中 _examples/todo/todo.go 就是一个完整可运行的同类实现其gqlgen.yml见 _examples/todo/gqlgen.yml还演示了如何把ID重映射为graphql.IntID以使用整数 ID。让代码生成可重复执行在resolver.go的package与import之间加入//go:generate go tool gqlgen generate之后即可递归触发全项目代码生成go generate ./...如何避免获取不会被用到的子对象官方 FAQ 第一个问题当 schema 存在嵌套或递归类型时比如type User { id: ID! name: String! friends: [User!]! }你并不希望每次查询 User 都顺带加载friends只有当客户端真正请求该字段时才去获取。gqlgen 提供了两种配置方式和一种内联写法。方式一使用自定义模型Custom Models写一个省略friends字段的手写模型type User struct { ID int Name string }然后在gqlgen.yml中引用它# gqlgen.yml models: User: model: github.com/you/pkg/model.User # go import path to the User struct abovegqlgen 会按 import path 绑定该结构体schema 中多出的friends字段因模型里不存在而自动生成 resolver。这种模型绑定机制的详细规则直接字段绑定、方法绑定、字段名不一致时的 tag 绑定等可参考 docs/content/reference/resolvers.md。方式二显式 resolverExplicit Resolvers如果想继续使用生成的模型可在gqlgen.yml里把该字段标记为需要 resolver# gqlgen.yml models: User: fields: friends: resolver: true # force a resolver to be generated无论采用哪种方式重新生成后都需要为friends提供 resolverfunc (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error) { // select * from user where friendid obj.ID return friends, nil }方式三用内联指令Inline Directives达到同样效果官方推荐在现代项目中优先使用指令形式。先在 schema 中声明 gqlgen 内置的goModel与goField指令完整声明见 docs/content/config.mddirective goModel( model: String models: [String!] ) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION directive goField( forceResolver: Boolean name: String omittable: Boolean type: String autoBindGetterHaser: Boolean forceGenerate: Boolean batch: Boolean ) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION type User goModel(model: github.com/you/pkg/model.User) { id: ID! goField(name: todoId) friends: [User!]! goField(forceResolver: true) # 当 omit_resolver_fields 开启时该字段仍会被生成到结构体中 data: String! goField(forceResolver: true, forceGenerate: true) }这里goField还演示了几个实用参数name用于把 GraphQL 字段绑定到 Go 结构体的不同字段名forceResolver强制生成 resolverforceGenerate在开启omit_resolver_fields时仍保留该字段。并发与 worker_limit字段 resolver 会在独立的 goroutine 中并发执行。并发度可通过配置属性worker_limit定制默认不限# gqlgen.yml exec: worker_limit: 1000该选项位于配置的exec段说明见 docs/content/config.md。在大 schema 上适当限制 worker 数量可以控制并发 goroutine 峰值。能把 ID 类型从 String 改成 Int 吗可以。GraphQL 的ID标量默认绑定到 Go 字符串通过gqlgen.yml的models段即可重映射models: ID: # The GraphQL type ID is backed by model: - github.com/99designs/gqlgen/graphql.IntID # a go integer - github.com/99designs/gqlgen/graphql.ID # or a go string - github.com/99designs/gqlgen/graphql.UintID # or a go uint这里有几个关键语义需要理解列表中第一个模型用作默认类型它会在「根据 schema 生成模型」以及「resolver 参数类型」两个场景下被固定使用其余模型仅用于「自动绑定」你手写模型中的字段——gqlgen 会根据字段的实际 Go 类型string/int/uint自动匹配这种匹配没有回退余地gqlgen 无法猜测你在某个具体上下文中想要哪种类型所以顺序即优先级。仓库中 _examples/todo/gqlgen.yml 就是这样配置的models: ID: model: # override the default id marshaller to use ints - github.com/99designs/gqlgen/graphql.IntID - github.com/99designs/gqlgen/graphql.ID同时注意GraphQL 规范中Int是 32 位有符号整数官方默认配置已把Int绑定到graphql.Int32详见 docs/content/config.md避免跨语言互操作时出现 64 位溢出问题。为什么接口会生成 getter如何关闭接口的 getter 方法IsName()自 v0.17.14 起引入目的是让你无需向下转型为具体类型即可访问接口的公共字段。但某些字段形态如 Relay 风格的 Connection 类型无法用简单 getter 实现。如果不想生成这些 getter在gqlgen.yml中加入# gqlgen.yml omit_getters: true该配置项在 codegen/config/config.go 中被解析为OmitGetters字段。同理接口与联合类型上的IsName()方法还可通过omit_interface_checks: true一并关闭见 docs/content/config.md。继续深入官方配套资源入门教程docs/content/getting-started.md 是更完整的逐步教程覆盖 Todo 服务的完整构建过程并演示autobind与「不急切获取 user」的配置演进真实示例仓库 _examples 目录包含大量可运行示例从 todo基础增删查、dataloader数据加载器、federationApollo Federation到 fileupload文件上传等参考文档docs/content/reference 收录了 resolver 绑定、模型生成、指令directives、标量、错误处理、插件等专题配置详解docs/content/config.md 列出了gqlgen.yml全部配置项及性能优化开关API 参考可直接查看go doc或pkg.go.dev上对github.com/99designs/gqlgen各包的说明问题反馈若发现 bug 或异常行为可在仓库的 Issues 区提交仓库根目录的 CONTRIBUTING.md 介绍了贡献流程。小结gqlgen 的核心工作流可以概括为写 schema → 跑go tool gqlgen generate→ 填充 resolver。通过gqlgen.yml的models映射、goModel/goField内联指令、autobind自动绑定你可以精确控制「哪些字段由模型直接提供、哪些字段延迟到 resolver 中按需加载」ID类型重映射与omit_getters等开关则让生成的代码更贴合业务约定。理解这些配置与生成逻辑的对应关系是高效使用 gqlgen 的关键一步。赞分享后端GraphQL代码生成【免费下载链接】gqlgengo generate based graphql server library项目地址https://gitcode.com/gh_mirrors/gq/gqlgen点击查看免费下载相关推荐gqlgen 入门实战用 Go 构建类型安全的 GraphQL 服务器gqlgen 入门实战用 Go 构建类型安全的 GraphQL 服务器 本篇教程基于 gqlgen 官方 Getting Started 指南展开完整演示如后端GraphQL代码生成gqlgen入门指南构建类型安全的GraphQL服务器gqlgen入门指南构建类型安全的GraphQL服务器 gqlgen是一个基于Go语言的GraphQL服务器生成器采用Schema优先的设计理念专注于提供后端GraphQL代码生成gqlgen 入门指南用 Schema-First 与代码生成构建类型安全的 GraphQL Go 服务器gqlgen 入门指南用 Schema First 与代码生成构建类型安全的 GraphQL Go 服务器 gqlgen 是 Go 生态中一套Schema后端GraphQL代码生成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表