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/

  • 相关阅读:
    hdu5728 PowMod
    CF1156E Special Segments of Permutation
    CF1182E Product Oriented Recurrence
    CF1082E Increasing Frequency
    CF623B Array GCD
    CF1168B Good Triple
    CF1175E Minimal Segment Cover
    php 正则
    windows 下安装composer
    windows apache "The requested operation has failed" 启动失败
  • 原文地址:https://www.cnblogs.com/brady-wang/p/15361835.html
Copyright © 2011-2022 走看看