官方文档地址 :https://gqlgen.com/getting-started/
本教程将带您完成使用 gqlgen 构建 GraphQL 服务器的过程,该服务器可以:
- 返回待办事项列表
- 创建新的待办事项
- 在待办事项完成时标记它们
您可以在此处找到本教程的完成代码
设置项目
为您的项目创建一个目录,并将其初始化为 Go Module:
$ mkdir gqlgen-todos
$ cd gqlgen-todos $ go mod init github.com/[username]/gqlgen-todos $ go get github.com/99designs/gqlgen
构建服务器
创建项目骨架
$ go run github.com/99designs/gqlgen init
这将创建我们建议的包布局。如果需要,您可以在 gqlgen.yml 中修改这些路径。
├── go.mod
├── go.sum
├── gqlgen.yml - The gqlgen config file, knobs for controlling the generated code.
├── graph
│ ├── generated - A package that only contains the generated runtime
│ │ └── generated.go
│ ├── model - A package for all your graph models, generated or otherwise
│ │ └── models_gen.go
│ ├── resolver.go - The root graph resolver type. This file wont get regenerated
│ ├── schema.graphqls - Some schema. You can split the schema into as many graphql files as you like
│ └── schema.resolvers.go - the resolver implementation for schema.graphql
└── server.go - The entry point to your app. Customize it however you see fit
定义您的架构
gqlgen 是一个模式优先的库——在编写代码之前,你使用 GraphQL模式定义语言来描述你的 API 。默认情况下,这会进入一个名为的文件, schema.graphql
但您可以根据需要将其分解为多个不同的文件。
为我们生成的模式是:
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! }
实现解析器
执行时,gqlgen 的generate
命令将模式文件 ( graph/schema.graphqls
) 与模型进行比较graph/model/*
,并且,只要可能,它将直接绑定到模型。这已经在init
运行时完成了。我们将在本教程的后面编辑模式,但现在,让我们看看已经生成的内容。
如果我们看一看,graph/schema.resolvers.go
我们将看到 gqlgen 无法匹配它们的所有时间。对我们来说是两次:
func (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
. 该graph/resolver.go
文件是我们声明应用程序依赖项的地方,例如我们的数据库。server.go
当我们创建图形时,它会被初始化一次。
type Resolver struct{ todos []*model.Todo }
回到graph/schema.resolvers.go
,让我们实现那些自动生成的解析器函数的主体。对于CreateTodo
,我们将使用math.rand
随机生成的 ID 简单地返回一个待办事项,并将其存储在内存中的待办事项列表中——在实际应用中,您可能会使用数据库或其他一些后端服务。
func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) { todo := &model.Todo{ Text: input.Text, ID: fmt.Sprintf("T%d", rand.Int()), 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 }
运行服务器
我们现在有一个工作服务器,可以启动它:
go run server.go
在浏览器中打开 http://localhost:8080。以下是一些要尝试的查询,从创建待办事项开始:
mutation createTodo { createTodo(input: { text: "todo", userId: "1" }) { user { id } text done } }
然后查询它:
query findTodos { todos { text done user { name } } }
不要急切地获取用户
这个例子很棒,但在现实世界中获取大多数对象的成本很高。我们不想在待办事项上加载用户,除非用户确实要求它。所以让我们用Todo
更真实的东西替换生成的模型。
创建一个名为的新文件 graph/model/todo.go
package model type Todo struct { ID string `json:"id"` Text string `json:"text"` Done bool `json:"done"` UserID string `json:"user"` }
笔记
默认情况下,gqlgen 将使用模型目录中与名称匹配的任何模型,这可以在
gqlgen.yml
.
并运行go run github.com/99designs/gqlgen generate
。
现在,如果我们查看,graph/schema.resolvers.go
我们可以看到一个新的解析器,让我们实现它并修复CreateTodo
.
func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) { todo := &model.Todo{ Text: input.Text, ID: fmt.Sprintf("T%d", rand.Int()), UserID: input.UserID, // fix this line } r.todos = append(r.todos, todo) return todo, nil } func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) { return &model.User{ID: obj.UserID, Name: "user " + obj.UserID}, nil }
收尾工作
在我们的resolver.go
,package
和之间import
,添加以下行:
//go:generate go run github.com/99designs/gqlgen
这个神奇的注释告诉go generate
我们要重新生成代码时要运行的命令。要在整个项目中递归运行 go generate,请使用以下命令:
go generate ./...
失败 执行 go get github.com/99designs/gqlgen/cmd@v0.14.0