This is Go library for building GraphQL client with gqlgen

Overview

gqlgenc

What is gqlgenc ?

This is Go library for building GraphQL client with gqlgen

Motivation

Now, if you build GraphQL api client for Go, have choice:

These libraries are very simple and easy to handle. However, as I work with gqlgen and graphql-code-generator every day, I find out the beauty of automatic generation. So I want to automatically generate types.

Installation

go get -u github.com/Yamashou/gqlgenc

How to use

Client Codes Only

gqlgenc base is gqlgen with plugins. So the setting is yaml in each format.
gqlgenc can be configured using a .gqlgenc.yml file

Load a schema from a remote server:

model:
  package: generated
  filename: ./models_gen.go # https://github.com/99designs/gqlgen/tree/master/plugin/modelgen
client:
  package: generated
  filename: ./client.go # Where should any generated client go?
models:
  Int:
    model: github.com/99designs/gqlgen/graphql.Int64
  Date:
    model: github.com/99designs/gqlgen/graphql.Time
endpoint:
  url: https://api.annict.com/graphql # Where do you want to send your request?
  headers: # If you need header for getting introspection query, set it
    Authorization: "Bearer ${ANNICT_KEY}" # support environment variables
query:
  - "./query/*.graphql" # Where are all the query files located?

Load a schema from a local file:

model:
  package: generated
  filename: ./models_gen.go # https://github.com/99designs/gqlgen/tree/master/plugin/modelgen
client:
  package: generated
  filename: ./client.go # Where should any generated client go?
models:
  Int:
    model: github.com/99designs/gqlgen/graphql.Int64
  Date:
    model: github.com/99designs/gqlgen/graphql.Time
schema:
  - "schema/**/*.graphql" # Where are all the schema files located?
query:
  - "./query/*.graphql" # Where are all the query files located?

Execute the following command on same directory for .gqlgenc.yml

gqlgenc

With gqlgen

Do this when creating a server and client for Go. You create your own entrypoint for gqlgen. This use case is very useful for testing your server.

package main

import (
	"fmt"
	"os"

	"github.com/Yamashou/gqlgenc/clientgen"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
)

func main() {
	cfg, err := config.LoadConfigFromDefaultLocations()
	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
		os.Exit(2)
	}
	queries := []string{"client.query", "fragemt.query"}
	clientPackage := config.PackageConfig{
		Filename: "./client.go",
		Package:  "gen",
	}

	clientPlugin := clientgen.New(queries, clientPackage)
	err = api.Generate(cfg,
		api.AddPlugin(clientPlugin),
	)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}

Documents

Comments

Japanese Comments

These codes have Japanese comments. Replace with English.

Subscription

This client does not support subscription. If you need a subscription, please create an issue or pull request.

Pre-conditions

clientgen is created based on modelgen. So if you don't have a modelgen, it may be a mysterious move.

Comments
  • Fixed issue when the operation has no name

    Fixed issue when the operation has no name

    An "UnamedX" name is used so that generated code compiles correctly.

    I went the easy way to start with this issue, however, I had another idea. What about instead of being unamed, the name is picked from the "operation" file if possible. It could be transformed such that it becomes a valid PascalCase identifier.

    Might be a bit intense and in almost in every cases, it's simply better to give a name to the operation, so the UnameX is most probably a more than good enough fix.

    opened by maoueh 11
  • feat(interface): generate client interface

    feat(interface): generate client interface

    attempting to address #81 and generate interfaces as well, I'm not familiar with this codebase, I'd like to know if I'm on right track.

    Also what else do I need to do? :)

    opened by cyberhck 8
  • (#51) add

    (#51) add "omitempty" option to nilable fields

    I faced the problem that is described in #51 and after short investigation came up with this solution. please let me know if tests needs to be added, etc.

    closes #51

    opened by blukai 8
  • Added possibility to only generate the operations and not the actual client code

    Added possibility to only generate the operations and not the actual client code

    Fixes #45

    Discussion

    What do you think about splitting the clientgen plugin in two halves? An opsgen plugin that would generate just the types and another plugin clientgen that would deal only with the client access code, that will become more important when Subscription will be supported.

    A direct copy should be possible at the expense of a good duplication of certain important structure & use cases. This would require some refactoring IMO to ensure the maximum of stuff can be shared between both plugin.

    That would remove the need for the new option config I added and turn the conditional generation by tweaking the top-level config.

    Maybe a good idea for the v2 work since it requires a fair amount of changes to merge it efficiently.

    opened by maoueh 8
  • add map support for json parser

    add map support for json parser

    Currently, there is no support for a schema with map[string]interface{}. This PR extends the decode method to unmarshal the map type.

    It was the main reason why I opened the previous issue: #141 All tests are passing right now

    opened by zreigz 7
  • Error: cannot use config.PackageConfig{...} (type config.PackageConfig) as type config.ExecConfig in field value

    Error: cannot use config.PackageConfig{...} (type config.PackageConfig) as type config.ExecConfig in field value

    This error occured in the latest version: v0.0.2: ../../../../go/pkg/mod/github.com/!yamashou/[email protected]/config/config.go:203:3: cannot use config.PackageConfig{...} (type config.PackageConfig) as type config.ExecConfig in field value

    opened by diep-it-dn 6
  • Unmarshal graphql response with json stdlib

    Unmarshal graphql response with json stdlib

    First of all, thank the author for providing this tool that can generate graphql client. But we also encountered some problems during use.

    Similar to the situation in #67, a scalar is defined in our schema, and the return value of the server is a map with an unfixed structure.

    We first specify the type to which scalar is mapped in the following way:

    models:
      Object:
        model: github.com/99designs/gqlgen/graphql.Map
    

    However, in the response of the parsing server, we got the following error:

    Error failed to decode data into response ... struct field for "xxx" doesn't exist in any of 1 places to unmarshal
    

    By reading the code, we found that gqlgenc will parse the response content through the graphqljson package, and always make judgments based on the way the target type is a structure.

    However, on the other hand, we also found that in the generated code, each field of the corresponding structure already has a corresponding json tag. We can directly use the json standard library for unmarshal.

    type LanguageFragment struct {
    	ID   string "json:\"id\" graphql:\"id\""
    	Name string "json:\"name\" graphql:\"name\""
    }
    

    So, can we use json instead to parse the response?

    opened by rgb-24bit 6
  • Added support to unmarshal json.RawMessage fields

    Added support to unmarshal json.RawMessage fields

    Problem

    Our graphql schema contains json scalars. It's mainly used for fields that require a bit more flexibility. Currently, the only way to use gqlgenc with json scalars is to pretend that all json scalars map to a specific struct and write a un/marshaller for that type. It works ok if you have 1 json scalar in your schema, but that's not our case.

    A better way of approaching that issue would be to use the json.RawMessage type. That way, you are pushing the unmarshalling logic down the consumer of the gqlgenc client. Unfortunately, this solution wasn't supported out of the box because the graphql decoder in graphqljson/graphql.go didn't handle the json.RawMessage type and it would result in an error.

    Solution

    Modify the decode function of the Decoder to handle the json.RawMessage type.

    Consideration

    In the decode function, when the code is at a point where it's in an object, read the key and found a matching field in the referred struct, the tie breaker for the matchingFieldValue is the position in the stacks (last matching one in d.vs). It's to reflect more or less what's happening when the value is actually processed (line 189-198).

    opened by jpgauthier 6
  • Conditional fragments (on sub-types of a union or an interface) should be represented as pointers

    Conditional fragments (on sub-types of a union or an interface) should be represented as pointers

    A Fragment is only applied on its type. It's therefor only applicable if the payload contains the data for that type.

    However fragments are currently represented as non-indirect (non-pointer) types in the generated client code (both v1 & v2). This leads all fragments subfields to be populated with default empty data in the JSON unmarshalling.

    If fragments were represented as pointers it would be possible to do a nil-check on the root fragment field to check types. As is, there's no good way to check if fragments are present.

    Consider a query using two fragments as such:

    query ConversationByIDQuery($id: ID!) {
        conversation(id: $id) {
            messages {
                ...answerFragment
                ...questionFragment
            }
        }
    }
    
    fragment answerFragment on ChatAnswerMessage {
        answer {
            ... on ChatSingleSelectAnswer {
                selectionId
            }
        }
    
    }
    
    fragment questionFragment on ChatQuestionMessage {
        question {
            ... on ChatSingleSelectQuestion {
                options {
                    id
                    text
                }
            }
        }
    }
    

    Furthermore, consider a schema in which the types referenced by the fragment are mutually exclusive. Perhaps two types implementing the same interface:

    query {
        conversation(id: ID!): Conversation
    }
    
    type Conversation {
      id: ID!
      messages: [ChatMessage!]!
    }
    type ChatAnswerMessage implements ChatMessage {
      answer: ChatSingleSelectAnswer!
    }
    type ChatSingleSelectAnswer {
      selectionId: ID!
    }
    type ChatQuestionMessage implements ChatMessage, ChatMessageWithText, ChatMessageWithUser {
      question: ChatSingleSelectQuestion,!
    }
    type ChatSingleSelectQuestion {
      options: [ChatSelectOption!]!
    }
    type ChatSelectOption {
      id: ID!
      text: String!
    }
    

    In this case the generated client payload does not allow you to distinguish which of the two types are represented.

    type ConversationByIDQuery struct {
    	Conversation *struct {
    		Messages []*struct {
    			Answer struct {
    				SelectionID string "json:\"selectionId\" graphql:\"selectionId\""
    			} "json:\"answer\" graphql:\"answer\""
    			Question struct {
    				Options []*struct {
    					ID   string "json:\"id\" graphql:\"id\""
    					Text string "json:\"text\" graphql:\"text\""
    				} "json:\"options\" graphql:\"options\""
    			} "json:\"question\" graphql:\"question\""
    		} "json:\"messages\" graphql:\"messages\""
    	} "json:\"conversation\" graphql:\"conversation\""
    }
    

    In most of the examples in the example directory here, this issue isn't visible because the fragments are applied directly to non-required (Type, not Type!) or list types (with the default config omit_slice_element_pointers: false).

    opened by adam-zethraeus 6
  • use standard json.Unmarshal instead of custom

    use standard json.Unmarshal instead of custom

    I have a very complex response from the API and the graphqljson.UnmarshalData throws errors. After changing to standard json.Unmarshal everything works fine.

    opened by zreigz 5
  • prevent overwrite Header by HTTPRequestOption function

    prevent overwrite Header by HTTPRequestOption function

    Fixes: https://github.com/Yamashou/gqlgenc/issues/109

    This PR prevents the situation when the Header "Content-Type" for type HTTPRequestOption func(req *http.Request) function is overwritten. I have implemented my own HTTPRequestOption function where I set it for multipart/form-data; boundary= to be able to upload files but finally, the req Header was different.

    opened by zreigz 5
  • erorr processing `type Query`

    erorr processing `type Query`

    Hello, I have queries defined as

    type Query {
      query1(): boolean
      query2(input: MyInput!): MyOutput!
    }
    

    as per https://www.apollographql.com/docs/apollo-server/schema/schema/#the-query-type:

    The Query type is a special object type that defines all of the top-level entry points for queries that clients execute against your server.

    same for type Mutation. Seems that gqlgenc is unable to process such files when generating operations: Unexpected token Name "type"

    Should it work, or what am I doing wrong?

    gqlgen generates server code well from those files.

    opened by glebsts 2
  • Error handling is quite verbose

    Error handling is quite verbose

    I would like to be able to check if there are network errors separate to graphql errors, and maybe log these as part of the generated client.

    Having to do the following seems like a lot of code to check if an entity didn't exist. I have User in my schema, not User!.

    Is this a gqlgenc issue or have I set up gqlgen incorrectly?

    if err != nil {
    	if handledError, ok := err.(*client2.ErrorResponse); ok {
    		if (*handledError.GqlErrors)[0].Message == sql.ErrNoRows.Error() {
    			c.JSON(http.StatusUnauthorized, gin.H{
    				"error": err.Error(),
    			})
    			return
    		}
    	}
    
    	log.Println(err)
    }
    
    opened by JamesArthurHolland 0
  • Customise GraphQL response with extensions

    Customise GraphQL response with extensions

    Currently I am using the PayPal / Braintree GraphQL endpoint: https://graphql.braintreepayments.com

    And it generates responses such as this:

    {
      "data": {
        "createClientToken": {
          "clientMutationId": null,
          "clientToken": "LCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpGVXpJMU5pSXNJbXRwWkNJNklqSXdNVGd3TkRJMk1UWXRjMkZ1WJNkltaDBkSEJ6T2k4dllYQnBMbk5oYm1SaWIzZ3VZbkpoYVc1MGNtVmxaMkYwWlhkaGVTNWpiMjBpZlEuZXlKbGVIQWlPakUyTmpjek1qQXhPVFlzSW1wMGFTSTZJ..."
        }
      },
      "extensions": {
        "requestId": "42629c2f-3d6e-573g-ae48-0c69410ab452"
      }
    }
    

    but it seems the client only parses the data portion of the response. ( and errors if they exist )

    Is there any way to fix this ?

    opened by Glagnar 4
  • Environment variables not working

    Environment variables not working

    I followed README instructions to setup the gqlgenc.yml file, specifically using env variables as explained:

    endpoint:
      url: https://api.annict.com/graphql # Where do you want to send your request?
      headers: # If you need header for getting introspection query, set it
        Authorization: "Bearer ${ANNICT_KEY}" # support environment variables
    

    Here's my configuration:

    ...
    endpoint:
      url: ${HASURA_GRAPHQL_ENDPOINT}
        headers: # If you need header for getting introspection query, set it
          Content-Type: "application/json"
          X-Hasura-Admin-Secret: ${HASURA_GRAPHQL_ADMIN_SECRET}
    ...
    

    but it doesn't work. I'm sure the endpoint works because if I hardcode those values everything goes well.

    Am I missing something?

    opened by Luca8991 0
  • optionally specify directory to load .gqlgenc.yml from

    optionally specify directory to load .gqlgenc.yml from

    I prefer to keep a root directory of my project clean and want to be able to specify a directory where to load .gqlgenc.yml file from.

    You can still run

    gqlgenc
    

    without any arguments to apply a current behavior of loading .gqlgenc.yml from a current directory, or you can specify the exact location of the .gqlgenc.yml file, by running app such as

    gqlgenc generate --configdir ./schemas
    

    in this case .gqlgenc.yml will be loaded from a ./schemas directory in current folder

    I have added urfave dependency into "gqlgenc" project, but main "gqlgen" project also uses it.

    opened by mobiletoly 1
Owner
Yamashou
Yamashou
The easiest way to make API documents for GraphQL

Document Generator for GraphQL gqldoc is now alpha gqldoc is command line tool to generate documents from GraphQL schema or your GraphQL endpoint. the

Kei Kamikawa 162 Dec 1, 2022
A port of the parser from graphql-js into golang

gqlparser This is a parser for graphql, written to mirror the graphql-js reference implementation as closely while remaining idiomatic and easy to use

Adam Scarr 399 Dec 4, 2022
gqlanalysis makes easy to develop static analysis tools for GraphQL in Go.

gqlanalysis gqlanalysis defines the interface between a modular static analysis for GraphQL in Go. gqlanalysis is inspired by go/analysis. gqlanalysis

null 36 Nov 1, 2022
Minimal UART client in Golang that dumps LPC1343 chips that are locked at CRP1.

Howdy y'all, This is a quick and dirty client for the UART bootloader of the LPC1343, and probably other bootloaders in that chip family. This client

Travis Goodspeed 13 Dec 2, 2022
This project contains an example that showcases different features from the official Go Client for Elasticsearch

Elasticsearch for Gophers This project contains an example that showcases different features from the official Go Client for Elasticsearch that you ca

Ricardo Ferreira 19 Oct 12, 2022
Utility functions for work with the Kubernetes Go-Client

go-k8s-utils This repository contains utils for the work with Kubernetes, in specific with the go-client library. Testing This package contains utils

Christoph Stäbler 2 Nov 17, 2022
GoLang-based client-side circuit breakers and helpers

Overview Example library for circuit breaking in GoLang. Written to support a blog post on https://www.wojno.com. Use this library in your SDK's to pr

Chris Wojno 0 Dec 5, 2021
Drone eReg: Demo client application for the PKI server's built-in UAV registry

UAV e-Registration: Demo UAV Registry Client A client to register UAVs in the built-in demo UAV registry of the UAVreg-PKI-server. Installation and Us

consider it GmbH 0 Jan 5, 2022
Govalid is a data validation library that can validate most data types supported by golang

Govalid is a data validation library that can validate most data types supported by golang. Custom validators can be used where the supplied ones are not enough.

null 61 Apr 22, 2022
Maintain a lower-bitrate copy of a music library in sync with the main copy.

msync Maintain a lower-bitrate copy of your music library, in sync with the main copy.

Chris Dzombak 18 Mar 6, 2022
Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs.

go-attr Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs. This package provides user frien

Shyamsunder Rathi 27 Jul 5, 2022
Go library for HTTP content type negotiation

Content-Type support library for Go This library can be used to parse the value Content-Type header (if one is present) and select an acceptable media

Elviss Strazdins 42 Jul 10, 2022
A tool and library for using structural regular expressions.

Structural Regular Expressions sregx is a package and tool for using structural regular expressions as described by Rob Pike (link).

Zachary Yedidia 41 Dec 7, 2022
A super simple Lodash like utility library with essential functions that empowers the development in Go

A simple Utility library for Go Go does not provide many essential built in functions when it comes to the data structure such as slice and map. This

Rahul Baruri 133 Nov 12, 2022
go-sysinfo is a library for collecting system information.

go-sysinfo go-sysinfo is a library for collecting system information. This includes information about the host machine and processes running on the ho

elastic 217 Nov 30, 2022
Molecule is a Go library for parsing protobufs in an efficient and zero-allocation manner

Molecule Molecule is a Go library for parsing protobufs in an efficient and zero-allocation manner. The API is loosely based on this excellent Go JSON

Richard Artoul 377 Dec 7, 2022
A Go (golang) library for parsing and verifying versions and version constraints.

go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version can sort a collection of versions properly, handles prerelease/beta versions, can increment versions, etc.

HashiCorp 1.3k Dec 7, 2022
A library for parsing ANSI encoded strings

Go ANSI Parser converts strings with ANSI escape codes into a slice of structs that represent styled text

Lea Anthony 37 Sep 20, 2022
A library for diffing golang structures

Diff A library for diffing golang structures and values. Utilizing field tags and reflection, it is able to compare two structures of the same type an

R3 Labs 669 Nov 26, 2022