昨天,我们在使用gqlgen
的时候,发现它默认没有int64
类型的标量,只有int
类型的标量。所以需要自定义一个int64
标量。
先说一下自定义标量的原理吧,这个在文档里面没有去解释,只是给出了一段代码,其他的就要自己去理解了。
自定义标量的原理就是,前端传递一个字符串,然后gqlgen
会自动调用我们实现的解析函数,去解析这个字符串,得到我们想要的类型。
现在,我们来实战一下。我们初始化项目:
1 | ~/codeDir/golangCode # mkdir scalars ; cd scalars ; go mod init scalars |
这里,我们是通过go module
这个包依赖管理工具来管理的。
因为gqlgen
是先定义schema
的然后再生成代码的,所以,我们需要先定义好我们的schema
。我们先创建文件:
1 | ~/codeDir/golangCode/scalars # touch schema.graphql |
内容如下:
1 | type Article { |
这里,我们简单的定义了一个类型Article
和一个查询article
。
OK
,现在我们来生成一下我们的代码:
1 | ~/codeDir/golangCode/scalars # gqlgen init |
我们可以在resolver.go
的Article
函数里面写我们的查询,这里,我们简单的返回一条记录即可:
1 | func (r *queryResolver) Article(ctx context.Context) (*Article, error) { |
然后,我们启动服务器:
1 | ~/codeDir/golangCode/scalars # go run server/server.go |
然后,我们在浏览器里面做如下请求:
1 | # Write your query or mutation here |
我们将会得到如下结果:
1 | { |
现在,我们来给article
增加一个查询参数,比如说时间,我们这里假定是int64
这个标量。我们修改schema
:
1 | scalar Int64 |
然后,我们需要去实现这个Int64
标量。我们创建一个新的文件,叫做int64.go
:
1 | ~/codeDir/golangCode/scalars # touch int64.go |
内容如下:
1 | package scalars |
我们需要去实现这里的UnmarshalGQL
函数和MarshalGQL
函数。这里,我们先简单的做个小测试,实现如下:
1 | package scalars |
然后,我们需要去修改gqlgen.yml
文件,指明我们的这个自定义的标量:
1 | # .gqlgen.yml example |
然后,我们需要把resolver.go
文件删除:
1 | ~/codeDir/golangCode/scalars # rm resolver.go |
然后重新生成:
1 | ~/codeDir/golangCode/scalars # gqlgen |
我们会发现,此时Article
这个queryResolver
多了一个参数time *Int64
,注意,这里的Int64
是我们scalars
包下自定义的那个Int64
,而不是golang
自带的那个int64
。
OK
,我们重新写一下这个Article
函数:
1 | func (r *queryResolver) Article(ctx context.Context, time *Int64) (*Article, error) { |
然后,我们重新启动服务器:
1 | ~/codeDir/golangCode/scalars # go run server/server.go |
我们发起如下请求,我们传递了一个时间参数"1"
:
1 | # Write your query or mutation here |
会得到如下的结果:
1 | { |
我们发现,返回的这个时间5
实际上就是我们在int64.go
文件里面实现的:
1 | func (i Int64) MarshalGQL(w io.Writer) { |
也就是说,我们w io.Writer
里面写了什么内容,就会返回给前端。
我们再看看终端的输出:
1 | ~/codeDir/golangCode/scalars # go run server/server.go |
打印出了10
,而不是客户端传递给服务器的1
。这个10
其实就是我们再int64.go
文件里面实现的:
1 | // UnmarshalGQL implements the graphql.UnMarshaler interface |
也就是说,我们在*i
里面填写的值,可以被Article queryResolver
的time *Int64
获取到。
OK
,那我们如何获取到前端传递过来的time
呢?
我们对int.go
里面的UnmarshalGQL
函数做如下修改:
1 | // UnmarshalGQL implements the graphql.UnMarshaler interface |
也就是说,前端传递给服务器的参数,我们可以在v interface{}
里面获取到。
然后重新启动服务器:
1 | ~/codeDir/golangCode/scalars # go run server/server.go |
然后做如下请求:
1 | # Write your query or mutation here |
结果:
1 | { |
因为我们在UnmarshalGQL
里面限定了time
必须为string
。
我们修改请求如下:
1 | # Write your query or mutation here |
结果:
1 | { |
我来看看终端的输出:
1 | ~/codeDir/golangCode/scalars # go run server/server.go |
说明我们在reoslver
里面获取到了客户端传递的这个时间字符串100
,并且成功的转换为了我们自定义的Int64
类型。
所以,对于自定义标量,总结下了实际上就是:
1 | 1、先定义好我们的两个解析函数 |
最后,GraphQL
好用。