@H_
404_0@Github提供的GraphQL接口非常全面,那么我们该如何搭建出自己的接口呢?好在GraphQL提供了很多语言的
解决方案。本文主要阐述如何用go搭建自己的GraphQL服务器。如果了解GraphQL建议先阅读
GraphQL — API查询语言 或相关资料。
graphql-go
An implementation of GraphQL in Go. Follows the official reference implementation
graphql-js
.
@H_
404_0@一套比较完善的框架,众所周知go的结构体对json非常友好,所以并不需要对数据有特殊的处理,还是很方便的。打开终端输入命令
@H_
404_0@
go get github.com/graphql-go/graphql
Object
@H_
404_0@在服务端编程中,编写的一切都可以称之为
对象(Object)。例如一个商品(goods)的实例可以有商品名(name)、价格(price)、购买
链接(url)三个字段。此时商品可以很自然的被称为一个object,
查询的语句可以写成:
{
goods{
name
price
url
}
}
@H_
404_0@如果此时我们要
查询商品和
文章两种object的信息:
/* query 可以省去 */
query{
goods{
name
}
article{
name
}
}
@H_
404_0@是否你已经发觉,query像一个大的object,它有goods和article两个字段。除此之外,mutation也是如此:
mutation{
addGoods(input:goodsInput){
name
}
}
@H_
404_0@这里的
addGoods
可以看做是一个可以处理参数的对象,也就是某种意义上的
函数。
@H_
404_0@总之,GraphQL服务端的编程就是一个又一个的对象将形成的嵌套结构(schema)组织起来,并对外提供服务。
query&mutation
@H_
404_0@为了防止低级
错误的发生,在当前pkg下新建一个名为query.go(随便起)的
文件。
import (
"github.com/graphql-go/graphql"
"errors"
)
@H_
404_0@
定义good object
type Goods struct {
ID string `json:"id"`
Name string `json:"name"`
Price float64`json:"price"`
Url string `json:"url"`
}
var goodsType = graphql.NewObject(
graphql.ObjectConfig{
Name: "Goods",Fields: graphql.Fields{
"id": &graphql.Field{
Type: graphql.String,},"name": &graphql.Field{
Type: graphql.String,"price": &graphql.Field{
Type: graphql.Float,"url": &graphql.Field{
Type: graphql.String,)
var goodsListType = graphql.NewList(goodsType)
@H_
404_0@
注意:数组相当于新的object类型。
@H_
404_0@
定义query object
var queryType = graphql.NewObject(
graphql.ObjectConfig{
Name: "Query",Fields: graphql.Fields{
// 无需处理参数
"goodsList": &graphql.Field{
Type:goodsListType,// 处理结构体的回调函数,直接返回处理完成的结构体即可
Resolve: func(p graphql.ResolveParams) (interface{},error) {
return result,err
},// 参数是id
"goods": &graphql.Field{
Type: goodsType,Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,Resolve: func(p graphql.ResolveParams) (interface{},error) {
// 获取参数
idQuery,isOK := p.Args["id"].(string)
if isOK {
return result,nil
}
err := errors.New("Field 'goods' is missing required arguments: id. ")
return nil,)
@H_
404_0@mutation定义基本相同,新建一个名为mutation.go的
文件:
@H_
404_0@
定义input object
var goodsInputType = graphql.NewInputObject(
graphql.InputObjectConfig{
Name: "goodsInput",Fields: graphql.InputObjectConfigFieldMap{
"name": &graphql.InputObjectFieldConfig{
Type: graphql.String,"price": &graphql.InputObjectFieldConfig{
Type: graphql.Float,"url": &graphql.InputObjectFieldConfig{
Type: graphql.String,)
@H_
404_0@
定义 mutation object
var mutationType = graphql.NewObject(
graphql.ObjectConfig{
Name: "Mutation",Fields: graphql.Fields{
"addGoods":&graphql.Field{
Type:goodsType,Args:graphql.FieldConfigArgument{
"input":&graphql.ArgumentConfig{
Type:goodsInputType,error) {
input,isOk := p.Args["input"].(map[string]string)
if !isOk{
err := errors.New("Field 'addGoods' is missing required arguments: input. ")
return nil,err
}
result := Goods{
Name:input["name"].(string),Price:input["price"].(float64),Url:input["url"].(string),}
// 处理数据
return result,)
@H_
404_0@然而,input类型并不能直接转换为struct,而是一个map[string]interface{}类型,还需要进行手动转换。
@H_
404_0@
定义schema
var schema,_ = graphql.NewSchema(
graphql.SchemaConfig{
Query: queryType,Mutation: mutationType,)
@H_
404_0@至此,我们的全部的object定义完成。
提供服务
@H_
404_0@graphql-go为我们提供了一个方便的接口,封装好的handler可以直接与go
自带的http包绑定。
package api
import "github.com/graphql-go/handler"
func Register() *handler.Handler {
h := handler.New(&handler.Config{
Schema: &schema,Pretty: true,GraphiQL: true,})
return h
}
func main() {
h := api.Register()
handler := cors.Default().Handler(h)
http.Handle("/graphql",handler)
fmt.Println("The api server will run on port : ",apiPort)
http.ListenAndServe(apiPort,nil)
}
@H_
404_0@打开浏览器,访问
http://localhost:apiPort/graphql,查看你自己的GraphiQL界面吧!
结束语
@H_
404_0@如果你觉得这样的
代码谈不上优雅,甚至非常丑陋,那就对了。因为我也这样觉得,看一看隔壁python的实现方式:
import graphene
class Query(graphene.ObjectType):
hello = graphene.String()
def resolve_hello(self,args,context,info):
return 'Hello world!'
schema = graphene.Schema(query=Query)
@H_
404_0@有没有涌来一口老血。
@H_
404_0@可能是受限与golang本身反射系统并不够完善,没有python各种各样的魔术
方法,没有泛型,或者说go本身不太适合编写框架类的
代码。在编写的过程中,冗余非常多,当然也可能是框架本身的问题
@H_
404_0@不可否认的是,go确实是非常不错的一门语言,虽然开发效率无法与python媲美,但是在多并发环境下,go表现出非常出色,同时拥有与C级别的运行速度和丰富的生态。
@H_
404_0@go还年轻,其他它越来越好!
原文链接:https://www.f2er.com/go/187305.html