Allow compatibility when using introspection derived client schema's (#145)
During generation we parse the schema using [`gqlparser.LoadSchema`](https://github.com/vektah/gqlparser/blob/2a3d320c0f1d31f404cc36f6cce8f7f93b016682/gqlparser.go#L11) over [here](https://github.com/Khan/genqlient/blob/a4aa6d9bb0f45cb71b3b7816742172011d96fbc1/generate/parse.go#L34). As you can see `gqlparser.LoadSchema` uses it's sub directory declared [`validator.LoadSchema`](https://github.com/vektah/gqlparser/blob/2a3d320c0f1d31f404cc36f6cce8f7f93b016682/gqlparser.go#L12) - but prepends a schema with [typical implicit declared types](https://github.com/vektah/gqlparser/blob/2a3d320c0f1d31f404cc36f6cce8f7f93b016682/validator/prelude.go#L5). Full server schema introspection exposes the entire schema explicitly, hence causing a clash with this prelude schema rendering introspection derived schemas to fail. Here I just introduce a two stage schema parsing step to accomodate both implicit and explicit sdl's. -- I have also added to the FAQ as per https://github.com/Khan/genqlient/issues/4 how we can use introspection to fetch the schema when using `genqlient`. Co-authored-by: Ben Kraft <[email protected]>
This commit is contained in:
co-authored by
Ben Kraft
parent
a4aa6d9bb0
commit
e0accbded1
+37
-1
@@ -96,7 +96,7 @@ bindings:
|
|||||||
|
|
||||||
Or, you can bind it to any other type, perhaps one with size-checked constructors; see the [`genqlient.yaml` documentation](genqlient.yaml) for more details.
|
Or, you can bind it to any other type, perhaps one with size-checked constructors; see the [`genqlient.yaml` documentation](genqlient.yaml) for more details.
|
||||||
|
|
||||||
### … let me json-marshal my response objects
|
### … let me json-marshal my response objects?
|
||||||
|
|
||||||
This is supported by default! All genqlient-generated types support both JSON-marshaling and unmarshaling, which can be useful for putting them in a cache, inspecting them by hand, using them in mocks (although this is [not recommended](#-test-my-graphql-apis)), or anything else you can do with JSON. It's not guaranteed that marshaling a genqlient type will produce the exact GraphQL input -- we try to get as close as we can but there are some limitations around Go zero values -- but unmarshaling again should produce the value genqlient returned. That is:
|
This is supported by default! All genqlient-generated types support both JSON-marshaling and unmarshaling, which can be useful for putting them in a cache, inspecting them by hand, using them in mocks (although this is [not recommended](#-test-my-graphql-apis)), or anything else you can do with JSON. It's not guaranteed that marshaling a genqlient type will produce the exact GraphQL input -- we try to get as close as we can but there are some limitations around Go zero values -- but unmarshaling again should produce the value genqlient returned. That is:
|
||||||
|
|
||||||
@@ -109,6 +109,42 @@ var respAgain MyQueryResponse
|
|||||||
err := json.Unmarshal(b, &resp)
|
err := json.Unmarshal(b, &resp)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### … let me use introspection to fetch my client schema?
|
||||||
|
|
||||||
|
This is currently not supported by default. You can however use a tool such as [gqlfetch](https://github.com/suessflorian/gqlfetch) to build your client schema using introspection and then let `genqlient` continue from there. Moreover, you can define yourself what happens when `go:generate` is run via managing your own _go runnable_ progam.
|
||||||
|
|
||||||
|
For example - suppose the file `generate/main.go`;
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/Khan/genqlient/generate"
|
||||||
|
"github.com/suessflorian/gqlfetch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
schema, err := gqlfetch.BuildClientSchema(context.Background(), "http://localhost:8080/query")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile("schema.graphql", []byte(schema), 0644); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
generate.Main()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This can now be invoked upon `go generate` via `//go:generate yourpkg/generate`.
|
||||||
|
|
||||||
## How do I make a query with …
|
## How do I make a query with …
|
||||||
|
|
||||||
### … a specific name for a field?
|
### … a specific name for a field?
|
||||||
|
|||||||
+13
-2
@@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/vektah/gqlparser/v2"
|
"github.com/vektah/gqlparser/v2"
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
"github.com/vektah/gqlparser/v2/parser"
|
"github.com/vektah/gqlparser/v2/parser"
|
||||||
"github.com/vektah/gqlparser/v2/validator"
|
"github.com/vektah/gqlparser/v2/validator"
|
||||||
)
|
)
|
||||||
@@ -31,9 +32,19 @@ func getSchema(globs StringList) (*ast.Schema, error) {
|
|||||||
sources[i] = &ast.Source{Name: filename, Input: string(text)}
|
sources[i] = &ast.Source{Name: filename, Input: string(text)}
|
||||||
}
|
}
|
||||||
|
|
||||||
schema, graphqlError := gqlparser.LoadSchema(sources...)
|
// Multi step schema validation
|
||||||
|
// Step 1 assume schema implicitly declares types that are required by the graphql spec
|
||||||
|
// Step 2 assume schema explicitly declares types that are required by the graphql spec
|
||||||
|
var (
|
||||||
|
schema *ast.Schema
|
||||||
|
graphqlError *gqlerror.Error
|
||||||
|
)
|
||||||
|
schema, graphqlError = gqlparser.LoadSchema(sources...)
|
||||||
if graphqlError != nil {
|
if graphqlError != nil {
|
||||||
return nil, errorf(nil, "invalid schema: %v", graphqlError)
|
schema, graphqlError = validator.LoadSchema(sources...)
|
||||||
|
if graphqlError != nil {
|
||||||
|
return nil, errorf(nil, "invalid schema: %v", graphqlError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema, nil
|
return schema, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user