学习Go的初学者开始使用gqlgen.

首先

因为一位正在创业的朋友说希望能得到一点帮助,我决定帮忙做一些与GraphQL相关的工作。那时我对golang和GraphQL都完全不了解,比起猫的手更加无用。

我的技能不足当然是一个原因,但我也感觉到相比熟悉的Python和JS等语言,缺乏对初学者友好的文章也是一个因素。

很少有易于理解的信息可供参考,这也可能是Go和GraphQL进入门槛较高的原因之一。

为了让像我这样的初学者能够快速开始使用Go + GraphQL,我会简单地记录一下关于gqlgen的内容。

※ 在讨论中,我们假设你已经对Go的基本语法和GraphQL的概念有一定了解。如果你对这些方面没有自信,阅读下面的文章可能会使你感到幸福。

    • Go言語:文法基礎まとめ

 

    • Web API初心者と学ぶGraphQL

 

    他言語から来た人がGoを使い始めてすぐハマったこととその答え

环境

操作系统 (CZXT)

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H114

$ go version
go version go1.15.5 darwin/amd64

gqlgen是什么?

只需要引用正式文本。

gqlgen 是一个使用Go语言编写的库,用于构建GraphQL服务器,无需任何繁琐的操作。

gqlgen 基于先定义模式(schema)的方法——您可以使用GraphQL模式定义语言来定义您的API。
gqlgen 优先考虑类型安全——你永远不会在这里看到 map[string]interface{}。
gqlgen 支持代码生成——我们会自动生成一些繁琐的部分,让您可以专注于快速构建您的应用程序。

为了那些对英语过敏的人,我尝试进行了意译并将其转换成了日语。

gqlgen是一个用于简便构建GraphQL服务器的Go语言库。

gqlgen基于”以模式为主”的方法,即按照GraphQL模式定义语言来定义API。
gqlgen优先考虑类型安全性,不再需要使用map[string]interface{}类型。
gqlgen使代码生成成为可能,不需要编写冗长的代码片段,能够专注于快速构建应用程序。

简而言之,这意味着现在可以轻松建立GraphQL服务器的Go库。让我们在运行gqlgen的同时实际观察一下它的流程,看看它有多简单。

试着搭建一个GraphQL服务器。

项目的创建和启动

暂时先试试看能否运行GraphQL。
这次我们创建一个名为”gqlgen-test”的项目。

# ディレクトリ作成
$ mkdir gqlgen-test
# Goプロジェクトとして初期化
$ go mod init gqlgen-test
# プロジェクト内に移動
$ cd gqlgen-test
# gqlgenをGOPATH/bin配下におく
$ go get github.com/99designs/gqlgen

目前的状态下,目录中还没有任何文件存在。

$ ls

接下来,让我们尝试使用gqlgen自动生成GraphQL服务器的框架。

# gqlgen initにより、GraphQLサーバーの骨組みを生成
$ go run github.com/99designs/gqlgen init

然后,会形成以下这样的结构。
(以下是tree命令的输出。)

├── gqlgen.yml
├── graph
│   ├── generated
│   │   └── generated.go
│   ├── model
│   │   └── models_gen.go
│   ├── resolver.go
│   ├── schema.graphqls
│   └── schema.resolvers.go
└── server.go

3 directories, 7 files

创建一个名为serger.go的go文件,然后立即启动它。

$ go run server.go

当您通过浏览器访问下面的网址时,将跳转至GraphQL查询界面。
http://localhost:8080/

image.png

执行查询

让我们立即输入查询语句。

query{
  todos{
    id
    text
  }
}

这意味着执行一个以“todos”命名的查询,并返回id和text。如果有人说“我没有定义名为 todos 的查询”,请查看 graph/schema.graphql。

# GraphQL schema example
#
# https://gqlgen.com/getting-started/

type Todo {
  id: ID!
  text: String!
  done: Boolean!
  user: User!
}

type User {
  id: ID!
  name: String!
}

type Query {
  todos: [Todo!]!
}

input NewTodo {
  text: String!
  userId: String!
}

type Mutation {
  createTodo(input: NewTodo!): Todo!
}

当我执行 `go run github.com/99designs/gqlgen init` 命令时,它自动为我生成了定义了 `todos` 的部分。

type Query {
  todos: [Todo!]!
}
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3439343736322f61396236396464372d303263362d636230332d326566302d3764396233343330653435362e706e67.png

接着,执行部收到如下消息。

{
  "errors": [
    {
      "message": "internal system error",
      "path": [
        "todos"
      ]
    }
  ],
  "data": null
}

原來如此。看起來數據為 null,內部系統發生錯誤。仔細回想一下,我們雖然在 schema.graphql 中寫了名為 todos 的查詢,但沒有記錄要返回什麼內容。

那么,让我们来看一下graph/schema.resolvers.go文件的内容。

package graph

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.

import (
    "context"
    "fmt"
    "gqlgen-test/gqlgen-test/graph/generated"
    "gqlgen-test/gqlgen-test/graph/model"
)

func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
    panic(fmt.Errorf("not implemented"))
}

func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
    panic(fmt.Errorf("not implemented"))
}

// Mutation returns generated.MutationResolver implementation.
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }

// Query returns generated.QueryResolver implementation.
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }

type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }

Todos函数只会抛出错误消息,没有返回任何响应的规格。

func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
    panic(fmt.Errorf("not implemented"))
}

让我们定义响应

让我们编辑解析器并定义响应,就像 schema.resolvers.go 一样,处理数据并返回作为响应的部分被称为解析器。

一旦使用Ctrl + C停止之前启动的服务器。
停止后,尝试编辑schema.resolver.go如下。

func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
    todo := []*model.Todo{
        {
            ID:   "1",
            Text: "サンプルテキスト",
            Done: true,
            User: &model.User{
                ID:   "001",
                Name: "山田太郎",
            },
        },
    }
    return todo, nil
}

※本来這裡應該是執行資料庫操作等的部分,但這次的主要目的是先試用GraphQL。為了簡化說明,我們將固定回應直接寫在這裡。關於與資料庫的連接部分,我希望能在另一篇文章中寫到。

同样地,我们也需要对resolver.go做如下编辑。

package graph

import "gqlgen-test/gqlgen-test/graph/model"

// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.

type Resolver struct {
    todos []*model.Todo
}

编辑完解析器后,返回项目的根目录并重新启动服务器。

$ go run server.go

请重新加载localhost:8080,并尝试以相同的查询方式执行。

image.png

这次应该会按照之前定义的通常情况返回响应。

{
  "data": {
    "todos": [
      {
        "id": "1",
        "text": "サンプルテキスト"
      }
    ]
  }
}

现在,我们在解析器中定义的键除了ID和文本外,还有完成状态和用户信息。
基于GraphQL的API可以通过查询来控制响应。
让我们也提取一下完成状态和用户信息吧!

query{
  todos{
    id
    text
    done
    user{
      id
      name
    }
  }
}

执行此操作时,您应该会直接得到您在解析函数中定义的结果作为响应。

{
  "data": {
    "todos": [
      {
        "id": "1",
        "text": "サンプルテキスト",
        "done": true,
        "user": {
          "id": "001",
          "name": "山田太郎"
        }
      }
    ]
  }
}

尝试自己定义查询

最后我想尝试自己定义查询。
如前所述,gqlgen基于模式优先的方法。
所以,当想要定义查询时,第一步是”定义模式”。

当停止服务器后,我们可以尝试编辑包含type Query的graph/schema.graphql文件。

type Query {
  todos: [Todo!]!
  testquery: String!
}

为了将模式更改反映到解析器中,请执行以下操作。

$ go run github.com/99designs/gqlgen generate

让我们再次看看graph/schema.resolver.go。
刚才不存在的查询语句Testquery现在存在了!

func (r *queryResolver) Testquery(ctx context.Context) (string, error) {
    panic(fmt.Errorf("not implemented"))
}

让我们修改代码,以返回自己喜欢的字符串。

func (r *queryResolver) Testquery(ctx context.Context) (string, error) {
    return "TestString", nil
}

让我们重新启动服务器,以确保能够得到期望的响应。

$ go run server.go
query{
  testquery
}
{
  "data": {
    "testquery": "TestString"
  }
}
image.png

把上述的流程逐步总结一下,结果如下,对吗?

    1. 项目生成

 

    1. 编辑模式

 

    1. 编辑解析器

 

    启动服务器

总结

就算對Go語言知識不多,或者覺得用Go寫代碼很麻煩的人,只要使用gqlgen能夠輕鬆地建立GraphQL服務器。我們只是缺乏能在日語上找到相關文章而已,一旦習慣使用,我認為這將無比方便。

由于我也是一个自以为写得很牛的初学者,所以如果您能指出明显的错误或需要更新的部分,我将不胜感激。

广告
将在 10 秒后关闭
bannerAds