本文是小编对gqlgen的初步构建做的整理,还望对你有所帮助。
gqlgen是一个用于构建GraphQL服务器的Go库。
序号 | 作用 |
---|---|
1 | gqlgen基于模式优先的方法 — 您可以使用GraphQL模式定义语言来定义API。 |
2 | gqlgen优先考虑类型安全 — 你不应该在这里看到map[string]interface{}。 |
3 | gqlgen启用了Codegen — 我们生成繁琐的bits,所以你可以专注于快速构建你的应用程序。 |
当你有这样的嵌套或递归模式:
type User {
id: ID!
name: String!
friends: [User!]!
}
您需要告诉gqlgen,只有当用户请求它时,它才应该获取好友。有两种方法可以做到这一点;
编写一个省略friends字段的自定义模型:
type User struct {
ID int
Name string
}
并参考gqlgen.yml中的模型:
//gqlgen.yml
models:
User:
model: github.com/you/pkg/model.User
//去导入路径到上面的用户结构
如果您想继续使用生成的模型,请在gqlgen.yml中显式地将该字段标记为需要解析器:
// gqlgen.yml
models:
User:
fields:
friends:
resolver: true
// 强制生成解析器
在完成上述操作并运行generate后,我们需要为好友提供一个解析器:
func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error) {
// select * from user where friendid = obj.ID
return friends, nil
}
你也可以使用内联配置指令来达到同样的效果:
directive @goModel(model: String, models: [String!]) on OBJECT
| INPUT_OBJECT
| SCALAR
| ENUM
| INTERFACE
| UNION
directive @goField(forceResolver: Boolean, name: String) 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)
}
你可以在配置中重新映射它,如下所示:
models:
ID: // The GraphQL type ID is backed by
model:
- github.com/99designs/gqlgen/graphql.IntID
//An go integer
- github.com/99designs/gqlgen/graphql.ID
// or a go string
这意味着gqlgen将能够自动绑定到你自己编写的模型的字符串或整数,但是这个列表中的第一个模型将被用作默认类型,并且它将一直被使用
创建一个目录作为项目目录,并初始化它:
$ 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
qlgen是一个模式优先的库——在编写代码之前,您需要使用GraphQL模式定义语言来描述API。默认情况下,这将被放入一个名为schema的文件中。但是,您可以将它分解成任意多个不同的文件。
自动生成的模式是:
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/*进行比较,只要可以,它就会直接绑定到模型上。
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中:
type Resolver struct{
todos []*model.Todo
}
当我们创建图表时,这是我们声明应用程序依赖的地方,比如数据库,它在服务器中初始化一次。
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上,除非用户确实要求这样做。因此,让我们用更真实的东西替换生成的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。我们可以看到一个新的解析器,我们来实现它并修复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
这个注释单纯告诉我们,如果要要重新生成代码时,要运行什么命令。
至此,结束。本文翻译于gqlgen官网,可前往https://gqlgen.com/getting-started/查看原文