start of wiring for configurable context

This commit is contained in:
Ben Kraft
2021-03-22 19:08:08 -07:00
parent 17a95fd4de
commit 59ca841a6b
19 changed files with 56 additions and 51 deletions
+2
View File
@@ -273,6 +273,8 @@ Additionally, users may want to get the client from the context, using a custom
This can all be configurable globally -- say you can decide whether to use context and client, and optionally provide the type of your context and/or a function that gets client from it, or something. We'll want to pick a good default before we have external users, so as not to break them, but it's easy enough to change the Khan-specific parts via codemod later.
**Decision:** It seems easy enough to allow all of this to be configured: you can specify no context, a specific context type, or the default of context.Context; and then if you want you can specify a way to get the client from context or a global. We'll need both hooks at Khan, and it's not much harder to add them in a generalizable way.
### Query extraction (for safelisting)
One thing we want to be able to do is to make it clear exactly what query-document (down to comments and whitespace) we will be sending in the query for the purposes of safelisting and querying based on hash. In the case where you have one query per file, that's easy, just use the whole file. But you may want to share fragments between queries, in which case this is trouble: you either need a way to include fragments from another file (and a defined concatenation order), or you need to have several queries per file, and either have genql extract the right parts (in a defined/reproducible way), or have it send up the full file and the operation name to use (in which case we should still encourage you to not do that unless you're hashing, so that you aren't sending up too much data). We could also allow configuration between the last two options (so if you don't care about hashing/safelisting you can auto-extract).
+27 -7
View File
@@ -5,15 +5,16 @@ import (
"go/token"
"io/ioutil"
"path/filepath"
"strings"
"gopkg.in/yaml.v2"
)
var defaultConfig = &Config{
Schema: "schema.graphql",
Queries: "queries.graphql",
Generated: "generated.go",
UseContext: true,
Schema: "schema.graphql",
Queries: "queries.graphql",
Generated: "generated.go",
ContextType: "context.Context",
}
type Config struct {
@@ -30,9 +31,19 @@ type Config struct {
// The filename to which to write the generated code; defaults to
// generated.go
Generated string `yaml:"generated"`
// Whether the generated helpers should accept a context.Context which will
// be used to make the request; defaults to true.
UseContext bool `yaml:"use_context"`
// Set to the fully-qualified name of a type which generated helpers should
// accept and use as the context.Context for HTTP requests. Defaults to
// context.Context; set to the empty string to omit context entirely.
ContextType string `yaml:"context_type"`
// TODO: implement client-getters
// If set, a snippet of Go code to get a *graphql.Client from the context
// (which will be named ctx). For example, this might do
// ctx.Value(myKey).(*graphql.Client). If omitted, client must be
// passed to each method explicitly.
// TODO: what if you want to do an import in this snippet, e.g. for a
// getter function, global var, or a context-key-type?
// TODO: what if you want to return err?
// ClientGetter string `yaml:"client_getter"`
}
func (c *Config) ValidateAndFillDefaults() error {
@@ -53,6 +64,15 @@ func (c *Config) ValidateAndFillDefaults() error {
return nil
}
func (c *Config) ContextPackage() string {
if c.ContextType == "" {
return ""
}
i := strings.LastIndex(c.ContextType, ".")
return c.ContextType[:i]
}
func ReadAndValidateConfig(filename string) (*Config, error) {
config := *defaultConfig
if filename != "" {
+7 -3
View File
@@ -3,7 +3,9 @@ package {{.Config.Package}}
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
{{- if .Config.ContextType -}}
"{{.Config.ContextPackage}}"
{{end}}
{{- if .ImportJSON -}}
"encoding/json"
{{end}}
@@ -11,11 +13,13 @@ import (
"github.com/Khan/genql/graphql"
)
{{/* TODO: type-assert that your ctx type implements context.Context */}}
{{.Types}}
{{range .Operations}}
{{.Doc}}
func {{.Name}}({{if $.Config.UseContext}}ctx context.Context, {{end}}client *graphql.Client{{range .Args}}, {{.GoName}} {{.GoType}}{{end}}) (*{{.ResponseName}}, error) {
func {{.Name}}({{if $.Config.ContextType}}ctx {{$.Config.ContextType}}, {{end}}client *graphql.Client{{range .Args}}, {{.GoName}} {{.GoType}}{{end}}) (*{{.ResponseName}}, error) {
{{- if .Args -}}
variables := map[string]interface{}{
{{range .Args -}}
@@ -24,7 +28,7 @@ func {{.Name}}({{if $.Config.UseContext}}ctx context.Context, {{end}}client *gra
}
{{end}}
var retval {{.ResponseName}}
err := client.MakeRequest({{if $.Config.UseContext}}ctx{{else}}context.Background(){{end}}, `{{.Body}}`, &retval, {{if .Args}}variables{{else}}nil{{end}})
err := client.MakeRequest({{if $.Config.ContextType}}ctx{{else}}nil{{end}}, `{{.Body}}`, &retval, {{if .Args}}variables{{else}}nil{{end}})
return &retval, err
}
{{end}}
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -37,7 +35,7 @@ func InputObjectQuery(client *graphql.Client, query UserQueryInput) (*InputObjec
}
var retval InputObjectQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query InputObjectQuery ($query: UserQueryInput) {
user(query: $query) {
id
+2 -2
View File
@@ -3,7 +3,7 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"encoding/json"
"github.com/Khan/genql/graphql"
)
@@ -95,7 +95,7 @@ func (v InterfaceNoFragmentsQueryRootTopicChildrenVideo) implementsGraphQLInterf
func InterfaceNoFragmentsQuery(client *graphql.Client) (*InterfaceNoFragmentsQueryResponse, error) {
var retval InterfaceNoFragmentsQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query InterfaceNoFragmentsQuery {
root {
id
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -22,7 +20,7 @@ func ListInputQuery(client *graphql.Client, names []string) (*ListInputQueryResp
}
var retval ListInputQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query ListInputQuery ($names: [String]) {
user(query: {names:$names}) {
id
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -18,7 +16,7 @@ type QueryWithAliasUser struct {
func QueryWithAlias(client *graphql.Client) (*QueryWithAliasResponse, error) {
var retval QueryWithAliasResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query QueryWithAlias {
User: user {
ID: id
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -19,7 +17,7 @@ type QueryWithDoubleAliasUser struct {
func QueryWithDoubleAlias(client *graphql.Client) (*QueryWithDoubleAliasResponse, error) {
var retval QueryWithDoubleAliasResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query QueryWithDoubleAlias {
user {
ID: id
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -25,7 +23,7 @@ const (
func QueryWithEnums(client *graphql.Client) (*QueryWithEnumsResponse, error) {
var retval QueryWithEnumsResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query QueryWithEnums {
user {
roles
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -21,7 +19,7 @@ type QueryWithSlicesUser struct {
func QueryWithSlices(client *graphql.Client) (*QueryWithSlicesResponse, error) {
var retval QueryWithSlicesResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query QueryWithSlices {
user {
emails
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -23,7 +21,7 @@ type QueryWithStructsUserAuthMethodsAuthMethod struct {
func QueryWithStructs(client *graphql.Client) (*QueryWithStructsResponse, error) {
var retval QueryWithStructsResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query QueryWithStructs {
user {
authMethods {
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -22,7 +20,7 @@ func SimpleInputQuery(client *graphql.Client, name string) (*SimpleInputQueryRes
}
var retval SimpleInputQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query SimpleInputQuery ($name: String!) {
user(query: {name:$name}) {
id
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -18,7 +16,7 @@ type SimpleQueryUser struct {
func SimpleQuery(client *graphql.Client) (*SimpleQueryResponse, error) {
var retval SimpleQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query SimpleQuery {
user {
id
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -19,7 +17,7 @@ type TypeNameQueryUser struct {
func TypeNameQuery(client *graphql.Client) (*TypeNameQueryResponse, error) {
var retval TypeNameQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query TypeNameQuery {
user {
__typename
+2 -2
View File
@@ -3,7 +3,7 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"encoding/json"
"github.com/Khan/genql/graphql"
)
@@ -73,7 +73,7 @@ func (v *UnionNoFragmentsQueryResponse) UnmarshalJSON(b []byte) error {
func UnionNoFragmentsQuery(client *graphql.Client) (*UnionNoFragmentsQueryResponse, error) {
var retval UnionNoFragmentsQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query UnionNoFragmentsQuery {
randomLeaf {
__typename
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -37,7 +35,7 @@ type UsesEnumTwiceQueryResponse struct {
func UsesEnumTwiceQuery(client *graphql.Client) (*UsesEnumTwiceQueryResponse, error) {
var retval UsesEnumTwiceQueryResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query UsesEnumTwiceQuery {
Me: user {
roles
+1 -3
View File
@@ -3,8 +3,6 @@ package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
@@ -37,7 +35,7 @@ func unexported(client *graphql.Client, query userQueryInput) (*unexportedRespon
}
var retval unexportedResponse
err := client.MakeRequest(context.Background(), `
err := client.MakeRequest(nil, `
query unexported ($query: UserQueryInput) {
user(query: $query) {
id
+1
View File
@@ -47,6 +47,7 @@ func (builder *typeBuilder) maybeWriteUnmarshal(fields []field) error {
return nil
}
builder.ImportJSON = true
builder.WriteString("\n\n")
return unmarshalTemplate.Execute(builder, data)
}
+3 -1
View File
@@ -50,7 +50,9 @@ func (client *Client) MakeRequest(ctx context.Context, query string, retval inte
return err
}
req = req.WithContext(ctx)
if ctx != nil {
req = req.WithContext(ctx)
}
resp, err := client.httpClient.Do(req)
if err != nil {
return err