分享
  1. 首页
  2. 文章

Go — 搭建GraphQL 服务端

myWsq · · 5246 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Github提供的GraphQL接口非常全面,那么我们该如何搭建出自己的接口呢?好在GraphQL提供了很多语言的解决方案。本文主要阐述如何用go搭建自己的GraphQL服务器。如果了解GraphQL建议先阅读GraphQL — API查询语言 或相关资料。

graphql-go

An implementation of GraphQL in Go. Follows the official reference implementation graphql-js.

一套比较完善的框架,众所周知go的结构体对json非常友好,所以并不需要对数据有特殊的处理,还是很方便的。打开终端输入命令

go get github.com/graphql-go/graphql

Object

在服务端编程中,编写的一切都可以称之为对象(Object)。例如一个商品(goods)的实例可以有商品名(name)、价格(price)、购买链接(url)三个字段。此时商品可以很自然的被称为一个object,查询的语句可以写成:

{
 goods{
 name
 price
 url
 }
}

如果此时我们要查询商品和文章两种object的信息:

/* query 可以省去 */
query{ 
 goods{
 name
 }
 article{
 name
 }
}

是否你已经发觉,query像一个大的object,它有goods和article两个字段。除此之外,mutation也是如此:

mutation{
 addGoods(input:goodsInput){
 name
 }
}

这里的addGoods可以看做是一个可以处理参数的对象,也就是某种意义上的函数

总之,GraphQL服务端的编程就是一个又一个的对象将形成的嵌套结构(schema)组织起来,并对外提供服务。

query&mutation

为了防止低级错误的发生,在当前pkg下新建一个名为query.go(随便起)的文件。

import (
 "github.com/graphql-go/graphql"
 "errors"
)

定义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)

注意:数组相当于新的object类型。

定义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, err
 },
 },
 },
 },
)

mutation定义基本相同,新建一个名为mutation.go的文件:

定义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,
 },
 },
 },
)

定义 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,
 },
 },
 Resolve: func(p graphql.ResolveParams) (interface{}, 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,err
 },
 },
 },
 },
)

然而,input类型并不能直接转换为struct,而是一个map[string]interface{}类型,还需要进行手动转换。

定义schema

var schema, _ = graphql.NewSchema(
 graphql.SchemaConfig{
 Query: queryType,
 Mutation: mutationType,
 },
)

至此,我们的全部的object定义完成。

提供服务

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)
}

打开浏览器,访问http://localhost:apiPort/graphql, 查看你自己的GraphiQL界面吧!

结束语

如果你觉得这样的代码谈不上优雅,甚至非常丑陋,那就对了。因为我也这样觉得,看一看隔壁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)

有没有涌来一口老血。

可能是受限与golang本身反射系统并不够完善,没有python各种各样的魔术方法,没有泛型,或者说go本身不太适合编写框架类的代码。在编写的过程中,冗余非常多,当然也可能是框架本身的问题

不可否认的是,go确实是非常不错的一门语言,虽然开发效率无法与python媲美,但是在多并发环境下,go表现出非常出色,同时拥有与C级别的运行速度和丰富的生态。

go还年轻,其他它越来越好!


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:myWsq

查看原文:Go — 搭建GraphQL 服务端

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
5246 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏