女主宣言

越来越多的项目中都能看到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", handler)log.Println("Server started at http://localhost:3000/graphql")log.Fatal(http.ListenAndServe(":3000", nil))
}

好了,以上就是全部实现!

启动服务器之后,我们可以使用GraphiQL查询一个具有特定id的文章,指定我们感兴趣的字段:

query {    post(id: 5) {        userIdidbodytitlecomments {idemailname}}
}

获取到以下返回信息:

{    "data": {        "post": {             "userId": 1,             "id": 5,             "title": "...",             "body": "...",                   "comments": [{                     "id": 21,                               "email": "...",                               "name": "..."},...]}}
}

如果我们在查询中去掉了评论,那么就不会发出获取评论的请求,我们只是简单地将选定的帖子作为响应。

完整的示例代码地址 https://github.com/zupzup/example-go-graphql。

总结

这个例子展示了如何使用一个简单的Go层将现有的REST API转换成GraphQL。我们使用的这个库,graphql-go工作得很好,提供了可靠的文档和良好的示例。

当然,有更简洁、更有趣的方法来定义这样的模式,但是由于技术等有限,我选择了这个解决方案,它的重点是清晰性。希望大家举一反三,自己结合实际去编写适合项目的实现。

HULK一线技术杂谈

由360云平台团队打造的技术分享公众号,内容涉及云计算、数据库、大数据、监控、泛前端、自动化测试等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享

基本操作:Go创建GraphQL API相关推荐

  1. laravel api_如何在现有的Laravel应用中获取即时GraphQL API

    laravel api by Karthikeya Viswanath 通过Karthikeya Viswanath 如何在现有的Laravel应用中获取即时GraphQL API (How to g ...

  2. 如何基于已有的 REST API 实现 GraphQL API

    这是「进击的Coder」的第 356 篇技术分享 作者:Tyler Hawkins 译者:samyu2000 校对者:PassionPenguin, k8scat 来源:掘金开发者社区 " ...

  3. 区块链/以太坊/DEX-在以太坊上构建 GraphQL API

    摘要 在做dex项目中,没有指导,只能自己摸索,本片文章的转载自https://learnblockchain.cn/article/2566 在操作过程中,遇到的最大难题应该是环境问题,会有各种依赖 ...

  4. amplify color_使用Amplify CLI创建Appsync API

    amplify color 在使用来自AWS的任何服务时,您可以通过其API,控制台或CLI工具(例如amplify,amplify)来实现,该工具专门用于与AWS配合使用,并使开发人员只需运行一些命 ...

  5. json graphql_使用json-graphql-server模拟GraphQL API

    json graphql You may find that you need to set up a fast GraphQL server to test your frontend app's ...

  6. aws api_带有AWS的GraphQL API和与React一起使用

    aws api GraphQL has become a go-to API implementation for developers looking to take advantage of fe ...

  7. 元数据驱动设计 —— 为动态移动应用创建Web API

    时间回到多年之前(当时我的头发还没这么稀疏),Google在4月1日这一天发布了Gmail,这不由得令许多人怀疑这个产品是否只是Google精心炮制的一个玩笑.但谁又能够去指责他们的怀疑呢?毕竟整个互 ...

  8. C语言实现单链表(带头结点)的基本操作(创建,头插法,尾插法,删除结点,打印链表)

    http://blog.csdn.net/xiaofeige567/article/details/27484137 C语言实现单链表(带头结点)的基本操作(创建,头插法,尾插法,删除结点,打印链表) ...

  9. react 生命挂钩_如何在GraphQL API中使用React挂钩来管理状态

    react 生命挂钩 In this blog post, we are going to learn - 在这篇博客中,我们将学习- What React hooks are什么是React钩子 H ...

最新文章

  1. PowerBuilder窗口之间传递多参数的方法
  2. viewer vue 文档_vue基于viewer实现的图片查看器
  3. 使用 OAS(OpenAPI标准)来描述 Web API
  4. oracle表压缩比,oracle的compress 特性介绍
  5. MySQL(5)---MySQL客户端工具的选择
  6. graphics | 基础绘图系统(四)——柱状图、直方图、扇形图、箱形图和函数图象...
  7. X 分钟速成 Python
  8. SLAM中边缘化与一致性
  9. Auto.jsMIUI小米手机锁屏界面无法上滑输入密码解锁的问题 以及如何输入密码进行解锁
  10. Toony Colors Pro 2项目分析——身体其他部位shader
  11. 冰点还原精灵使用技巧
  12. Faster-RCN训练和入门使用--Pytorch版本
  13. 谷粒商城项目环境搭建
  14. 二层华三交换机连接三层思科交换机,trunk,vlan划分
  15. 闲鱼触达系统背后——我想更懂你
  16. windows 中 vpn连接提示, 虚拟专用网络 由于RAS/虚拟专用网络,服务器上配置的某个策略,服务器用于验证用户名和密码的身份验证方法可能与连接配置文件中的身份证验证方法不匹配
  17. 股市逃顶的技巧和方法
  18. python控制安卓手机的闹钟_【玩转Python】为女朋友打造一款智能语音闹钟
  19. 谷歌浏览器如何一键清除所有断点
  20. matlab怎么把音频变成信号_matlab实现声音信号的频谱分析

热门文章

  1. Linux磁盘读写速率测试
  2. 设计模式之不简单的工厂模式(三)
  3. python 服务器框架_python 服务器框架
  4. C# 错误 175: 具有固定名称“System.Data.SQLite.EF6”的 ADO.NET 提供程序未在计算机或应用程序配置文件中注册或无法加载
  5. 解决Ubuntu18.04 No wifi adapter found
  6. Spring Boot、Spring Cloud、Dubbo的区别
  7. Ajax(二)-XMLHttpRequest(核心)对象的属性和方法
  8. cass绘制围墙lisp_CASS中用LISP完成高程值的可视化处理
  9. 导致出现404的原因以及解决方案
  10. 光源时间_D65光源对色灯箱的操作步骤及作业标准