zoukankan      html  css  js  c++  java
  • 使用GQLGEN搭建GRAPHQL的GO服务端

     

    添加依赖

    require (
    	github.com/99designs/gqlgen v0.11.3
    	github.com/vektah/gqlparser/v2 v2.0.1
    )
    

    编写SCHEMA

    在项目根目录创建文件夹,graph,在graph文件夹中新建schema.graphqls文件,在其中编写schema定义,比如

    type Query {
        hello: String
    }
    

    生成GO代码

    在项目根目录新建go源代码,内容为

    package main
    
    import "github.com/99designs/gqlgen/cmd"
    
    func main() {
    	cmd.Execute()
    }
    

    接下来,使用命令生成相关go代码

    go run 源代码文件名.go init
    

    此时命令行会输出

    validation failed: packages.Load: -: package test/graph/model is not in GOROOT ...
    

    这是因为我们没有在graph文件夹中,创建graph的modal文件夹及源文件(因为我们没有定义其他type,不需要用到,不影响)
    此时执行后,目录结构为

    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----         2020/5/5     16:08                graph
    -a----         2020/5/4     17:44            110 go.mod
    -a----         2020/5/4     17:44           7599 go.sum
    -a----         2020/5/4     17:15             94 gqlgen.go
    -a----         2020/5/5     16:08           1667 gqlgen.yml
    -a----         2020/5/5     16:08            635 server.go
    

    其中的gqlgen.yml和server.go是自动生成的代码,server.go就是运行这个graph服务端程序的go代码,默认使用8080端口,直接将其作为普通go程序运行则代表启动服务端,这里还不能启动,因为我们定义的schema里的查询还没有编写实现

    package main
    
    import (
    	"log"
    	"net/http"
    	"os"
    	"test/graph"
    	"test/graph/generated"
    
    	"github.com/99designs/gqlgen/graphql/handler"
    	"github.com/99designs/gqlgen/graphql/playground"
    )
    
    const defaultPort = "8080"
    
    func main() {
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = defaultPort
    	}
    
    	srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
    
    	http.Handle("/", playground.Handler("GraphQL playground", "/query"))
    	http.Handle("/query", srv)
    
    	log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
    	log.Fatal(http.ListenAndServe(":"+port, nil))
    }
    

    gqlgen.yml是默认的配置文件,配置了如何读取graph文件夹下内容进行go代码生成,因为刚刚我们没有编写这个文件,所以会使用默认配置,内容如下

    # Where are all the schema files located? globs are supported eg  src/**/*.graphqls
    schema:
      - graph/*.graphqls
    
    # Where should the generated server code go?
    exec:
      filename: graph/generated/generated.go
      package: generated
    
    # Uncomment to enable federation
    # federation:
    #   filename: graph/generated/federation.go
    #   package: generated
    
    # Where should any generated models go?
    model:
      filename: graph/model/models_gen.go
      package: model
    
    # Where should the resolver implementations go?
    resolver:
      layout: follow-schema
      dir: graph
      package: graph
    
    # Optional: turn on use `gqlgen:"fieldName"` tags in your models
    # struct_tag: json
    
    # Optional: turn on to use []Thing instead of []*Thing
    # omit_slice_element_pointers: false
    
    # Optional: set to speed up generation time by not performing a final validation pass.
    # skip_validation: true
    
    # gqlgen will search for any type names in the schema in these go packages
    # if they match it will use them, otherwise it will generate them.
    autobind:
      - "test/graph/model"
    
    # This section declares type mapping between the GraphQL and go type systems
    #
    # The first line in each type will be used as defaults for resolver arguments and
    # modelgen, the others will be allowed when binding to fields. Configure them to
    # your liking
    models:
      ID:
        model:
          - github.com/99designs/gqlgen/graphql.ID
          - github.com/99designs/gqlgen/graphql.Int
          - github.com/99designs/gqlgen/graphql.Int64
          - github.com/99designs/gqlgen/graphql.Int32
      Int:
        model:
          - github.com/99designs/gqlgen/graphql.Int
          - github.com/99designs/gqlgen/graphql.Int64
          - github.com/99designs/gqlgen/graphql.Int32
    
    

    正是其中的以下代码,指定了读取这个路径文件作为modal文件,而我们没有提供,在刚刚运行才会有validate fail的提示

    model:
      filename: graph/model/models_gen.go
      package: model
    

    如果需要,我们也可以创建modal文件夹,在modal文件夹中编写models_gen.go文件,如下,每个字段右侧的 ``注释代表标明json序列化时的键值名称

    package model
    
    type NewTodo struct {
    	Text   string `json:"text"`
    	UserID string `json:"userId"`
    }
    
    type Todo struct {
    	ID   string `json:"id"`
    	Text string `json:"text"`
    	Done bool   `json:"done"`
    	User *User  `json:"user"`
    }
    
    type User struct {
    	ID   string `json:"id"`
    	Name string `json:"name"`
    }
    

    而在graph文件夹中,也生成了对应go代码

    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----         2020/5/5     16:08                generated
    -a----         2020/5/5     16:08            184 resolver.go
    -a----         2020/5/5     11:35             32 schema.graphqls
    -a----         2020/5/5     16:08            544 schema.resolvers.go

    其中的generated文件夹中包含一个generated.go,是框架的处理逻辑封装,一般由编译生成不去修改,比如刚刚的hello,会被编译为一个接口

    type QueryResolver interface {
    	Hello(ctx context.Context) (*string, error)
    }
    

    我们唯一需要关注的是schema.resolvers.go这个文件,其中定义了每个查询的返回结果,我们需要在其中用golang编写查询结果的实现

    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"
    	"test/graph/generated"
    )
    
    func (r *queryResolver) Hello(ctx context.Context) (*string, error) {
    	panic(fmt.Errorf("not implemented"))
    }
    
    // Query returns generated.QueryResolver implementation.
    func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
    
    type queryResolver struct{ *Resolver }
    

    像是这个,刚刚的hello在这里被编译为一个go的函数,所以我们通过编写这个函数的实现,决定返回给客户端的内容,比如返回字符串helllo

    package graph
    
    import (
    	"context"
    	"test/graph/generated"
    )
    
    func (r *queryResolver) Hello(ctx context.Context) (*string, error) {
    	retval := string("hello")
    	return &retval,nil
    }
    
    func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
    
    type queryResolver struct{ *Resolver }
    

    运行服务端

    实现了查询就可以启动服务端了,在项目根目录执行

    go run .server.go
    
    • 1

    会看到

    connect to http://localhost:8080/ for GraphQL playground
    
    • 1

    此时访问该地址,就可以看到服务端提供的web查询页面,在左边的输入框编写查询,点击播放按钮即可在右边看到服务端返回的查询结果
    gqlgen的web服务端

    https://www.freesion.com/article/1315615190/

  • 相关阅读:
    QTP问题:查询文件被占用
    QTP自动化
    Spring: $Proxy9 cannot be cast to test.spring.service.impl.PersonServiceImpl2
    spring: White spaces are required between publicId and systemId.
    spring学习1
    MyBatis学习(1)
    从技术人员的角度看,公司怎么生存?
    一天一工程总结系列-7.7-KVOController
    appCode使用说明
    ios开发中的字符串常量如何处理
  • 原文地址:https://www.cnblogs.com/brady-wang/p/15361835.html
Copyright © 2011-2022 走看看