专栏名称: HULK一线技术杂谈
HULK是360的私有云平台,丰富的一线实战经验,为你带来最有料的技术分享
目录
相关文章推荐
疯狂区块链  ·  你还没理解“钱的重要性” ·  12 小时前  
疯狂区块链  ·  特斯拉股票还能不能买? ·  昨天  
疯狂区块链  ·  财务自由后你想干什么? ·  2 天前  
白话区块链  ·  以太坊现货ETF持续流入,为何ETH价格却毫 ... ·  2 天前  
51好读  ›  专栏  ›  HULK一线技术杂谈

基本操作:Go创建GraphQL API

HULK一线技术杂谈  · 公众号  ·  · 2018-04-17 18:08

正文


女主宣言

越来越多的项目中都能看到GraphQL的身影,不知道大家在项目中有没有使用过GraphQL呢?今天给大家分享一下使用Go,来创建基础 GraphQL API ,供大家参考学习。

PS:丰富的一线技术、多元化的表现形式,尽在“ HULK一线技术杂谈 ”,点关注哦!

引言

随着时间推移,我们在越来越多的项目中,都可以发现GraphQL的身影。

从几个方面看,包括图形化的数据、多个分布式团队和高度版本化的api,以及关于类型安全和文档的问题。GraphQL看起来非常适合许多不同的应用程序。

本文的目标不是去介绍GraphQL的基础知识,而是在实际场景中看到它的实际操作。当计划将现有的REST API移动到GraphQL时,需要引入一个转换层,以实现平稳过渡。

在本篇文章中,我们将使用jsonplaceholder作为我们用GraphQL包装的API。这里有几个用于graphQL的库,在本篇文章示例中,将使用graphql-go和graphql-go-handler。

我们的目标是从jsonplaceholder获取文章和评论,最后以一种通过ID获取文章的方式,如果API使用者希望获取评论,则通过GraphQL将评论嵌套到文章中。

让我们开始吧。

开始实现

首先,我们为文章和评论定义数据模型:

type Post struct {
    UserID int    `json:"userId"`
    ID     int    `json:"id"`
    Title  string `json:"title"`
    Body   string `json:"body"`
}

type Comment struct {    PostID int    `json:"postId"`    ID     int    `json:"id"`    Name   string `json:"name"`    Email  string `json:"email"`    Body   string `json:"body"`
}

我们定义 fetchPostByiD(id)函数,它用来调用http://jsonplaceholder.typicode.com/posts/${id} 并将生成的JSON转换成Post。当然,还有一个fetchCommentByPostId(post.ID)助手函数,它对注释做同样的事情,从http://jsonplaceholder.typico/posts/${id}/注释中获取数据,并将其转换为[]Comment。

然后我们继续创建graphQL模式。我们从定义queryType开始,它是模式的根:

func createQueryType(postType *graphql.Object)




    
 graphql.ObjectConfig {
   return graphql.ObjectConfig{Name: "QueryType", Fields: graphql.Fields{
       "post": &graphql.Field{            Type: postType,            Args: graphql.FieldConfigArgument{
               "id": &graphql.ArgumentConfig{                    Type: graphql.NewNonNull(graphql.Int),                },            },            Resolve: func(p graphql.ResolveParams) (interface{}, error) {                id := p.Args["id"]                v, _ := id.(int)                log.Printf("fetching post with id: %d", v)
               return fetchPostByiD(v)            },        },    }} }

根查询类型只有一个字段 —— post。这个字段是由postType定义的,我们稍后会看到。它只接受一个名为id的参数。

文章通过从p.Args中解析出id,并将它传递给fetchPostsByID,返回已获取和转换后的Post以及错误信息。

接下来,我们定义postType,这很有趣。我们基本上只是把post字段从数据模型映射到graphQL类型,但我们也添加了comments字段。如果客户端显式地想要取回它们,那么评论的Resolve函数才会被调用。

为了解决评论,我们使用p.Source来访问这个查询的“父”。它为我们提供了一个Post实例*Post——已获取的文章。使用这篇文章的id,我们可以获取评论:

func createPostType(commentType *graphql.Object) *graphql.Object {
   return graphql.NewObject(graphql.ObjectConfig{        Name: "Post",        Fields: graphql.Fields{
           "userId": &graphql.Field{                Type: graphql.NewNonNull(graphql.Int),            },
           "id": &graphql.Field{                Type: graphql.NewNonNull(graphql.Int),            },
           "title": &graphql.Field{                Type: graphql.String,            },
           "body": &graphql.Field{                Type: graphql.String,            },
           "comments": &graphql.Field{                Type: graphql.NewList(commentType),                Resolve: func(p graphql.ResolveParams) (interface{}, error) {                    post, _ := p.Source.(*Post)                    log.Printf("fetching comments of post with id: %d", post.ID)
                   return fetchCommentsByPostID(post.ID)                },            },        },    }) }

在模式中唯一要定义的类型是commentType,这很无聊,因为它只将数据模型的字段映射到graphQL类型:

func createCommentType() *graphql.Object {
   return graphql.NewObject(graphql.ObjectConfig{
       Name: "Comment",
       Fields: graphql.Fields{
           "postid": &graphql.Field{
               Type: graphql.NewNonNull(graphql.Int),            },
           "id": &graphql.Field{
               Type: graphql.NewNonNull(graphql.Int),            },
           "name": &graphql.Field{
               Type: graphql.String,            },
           "email": &graphql.Field{
               Type: graphql.String,            },
           "body": &graphql.Field{
               Type: graphql.String,            },        },    }) }

好了,我们的模式被定义了,剩下的就是把它们放在一起。

我们实例化一个graphQL模式并将其传递给graphql-go-handler,它是一个http中间件,它帮助我们处理graphQL查询。然后我们简单地启动一个http服务器,它的返回处理程序被路由到/graphql。

这像这样:

func main() {
    schema, err := graphql.NewSchema(graphql.SchemaConfig{
        Query: graphql.NewObject(
            createQueryType(
                createPostType(
                    createCommentType(),
                ),
            ),
        ),
    })
   if err != nil {        log.Fatalf("failed to create schema, error: %v", err)    }    handler := gqlhandler.New(&gqlhandler.Config{        Schema: &schema,    })    http.Handle("/graphql"






请到「今天看啥」查看全文