go gqlgen使用方法

2,440 阅读3分钟

什么是gqlgen?

gqlgen是一个go语言封装的一个graphql包,使用go语言对外暴露graphql接口

优点:gqlgen只依赖graphql schema。你只需要写好graphql schema就行,通过命令生成相关代码,包括接口、请求参数结构、返回参数结构,你只需要实现接口即可。

开始使用gqlgen

新建一个项目

make gqlgen-todos

初始化go mod

go mod init
go mod tidy

生成基础代码

go run github.com/99designs/gqlgen init

注意:刚开始可能因为没有地方引用gqlgen而导致本地没有github.com/99designs/gqlgen,可以先新建一个空文件,引入gqlgen

import (
	_ "github.com/99designs/gqlgen"
)

然后go mod就可以引入gqlgen包了。

.
├── 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.yml

gqlgen的配置文件,gqlgen命令生成代码的时候会用到,可以指定schema路径、代码生成路径等

graph/schema.graphqls

这个文件是graphql schema文件,gqlgen给出我们生成的,这就是我们写schema的地方,其他代码都是根据它生成的。我们也可以自己在里面写自己的schema并用go run github.com/99designs/gqlgen命令重新生成代码,我们也可以自己新建一个schema,并在gqlgen.yml文件中指定它的位置

# Where are all the schema files located? globs are supported eg  src/**/*.graphqls
schema:
  - graph/*.graphqls

graph/generated/generated.go

运行时会调用的代码,包括接口定义,以及外部请求进来后先进入这个文件,然后对请求进行分发

graph/model/models_gen.go

自动生成的、schema中定义的type,input等所有的结构体

graph/schema.resolve.go

请求的入口,会对每个query,mutation生成对应的入口函数

graph/resolve.go

mutationResolver和queryResolver会继承它

type Resolver struct {
}

mutation和query公共的操作可以定义在Resolve上。

service.go

这个是main函数,开启http端口开始监听

自己写一个demo

为了更加方便体验gqlgen,避免不知道它在生成代码的时候做了什么,我们不要用它自带的schema文件,自己重新定义,并且更换位置,从头到尾体验一下。

.
├── go.mod
├── go.sum
├── gqlgen.yml
├── graph
│   ├── generated
│   │   └── generated.go
│   ├── model
│   │   └── models_gen.go
│   ├── mutation.resolvers.go
│   ├── query.resolvers.go
│   └── resolver.go
├── schema
│   ├── mutation.graphqls
│   ├── query.graphqls
│   ├── student.graphqls
│   └── teacher.graphqls
└── server.go

定义schema

在根目录下新建一个schema文件夹,定义了几个schema文件
schema/student.graphqls

type Student {
  id: ID!
  name: String!
  tel: String
  
  is_deleted: Boolean!
}

input NewStudent {
  name: String!
  tel: String
}

input ModifyStudentName {
  id: ID!
  name: String!
}

input DeleteStudent {
  id: ID!
}

schema/teacher.graphqls

type Teacher {
    id: ID!
    name: String!
    students: [Student!]!
}

input NewTeacher {
    name: String!
    student_ids: [ID!]!
}

schema/query.graphqls

type Query {
  students: [Student!]!
  teachers: [Teacher!]!
}

schema/mutation.graphqls

type Mutation {
  createStudent(input: NewStudent!): Student!
  modifyStudent(input: ModifyStudentName!): Boolean!
  deleteStudent(input: DeleteStudent!): Boolean!

  createTeacher(input: NewTeacher!): Teacher!
}

生成代码

go run github.com/99designs/gqlgen

改query

graph/query.resolvers.go

package graph

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.

import (
	"context"
	"gqlgen-todos/graph/generated"
	"gqlgen-todos/graph/model"
)

func (r *queryResolver) Students(ctx context.Context) ([]*model.Student, error) {
	return r.students, nil
}

func (r *queryResolver) Teachers(ctx context.Context) ([]*model.Teacher, error) {
	return r.teachers, nil
}

// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }

type queryResolver struct{ *Resolver }

改mutation

graph/mutation.resolvers.go

package graph

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.

import (
	"context"
	"fmt"
	"gqlgen-todos/graph/generated"
	"gqlgen-todos/graph/model"
	"math/rand"
)

func (r *mutationResolver) CreateStudent(ctx context.Context, input model.NewStudent) (*model.Student, error) {
	s := &model.Student{
		ID:   fmt.Sprintf("%s%d", input.Name, rand.Int()),
		Name: input.Name,
		Tel:  input.Tel,
	}
	r.students = append(r.students, s)
	return s, nil
}

func (r *mutationResolver) ModifyStudent(ctx context.Context, input model.ModifyStudentName) (bool, error) {
	for i := range r.students {
		if r.students[i].ID == input.ID {
			r.students[i].Name = input.Name
			return true, nil
		}
	}

	return false, nil
}

func (r *mutationResolver) DeleteStudent(ctx context.Context, input model.DeleteStudent) (bool, error) {
	for i := range r.students {
		if r.students[i].ID == input.ID {
			r.students[i].IsDeleted = true
			return true, nil
		}
	}

	return false, nil
}

func (r *mutationResolver) CreateTeacher(ctx context.Context, input model.NewTeacher) (*model.Teacher, error) {
	t := &model.Teacher{
		ID:   fmt.Sprintf("%s%d", input.Name, rand.Int()),
		Name: input.Name,
	}

	for i := range r.students {
		for j := range input.StudentIds {
			if input.StudentIds[j] == r.students[i].ID {
				t.Students = append(t.Students, r.students[i])
			}
		}
	}

	return t, nil
}

// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }

type mutationResolver struct{ *Resolver }

运行

go run server.go

测试

创建学生

image.png

修改学生

modifyStudent

image.png

删除学生

image.png

查询学生

image.png

创建老师

先创建2个学生

image.png 然后创建老师

image.png

查询老师

image.png

源代码

gqlgen_demo

总结

这篇文章主要介绍了一下go使用graphql,利用gqlgen包,参考文件[3]中有关于graphql的语法可以学习一下。

参考

[1]getting-started
[2]gqlgen
[3]graphql学习
[4]graphql和grpc之间的转换
[5]gqlgen_demo