From 59ca841a6b635fa3f62ae19d2dea2ddcd300c225 Mon Sep 17 00:00:00 2001 From: Ben Kraft Date: Mon, 22 Mar 2021 19:08:08 -0700 Subject: [PATCH] start of wiring for configurable context --- DESIGN.md | 2 ++ generate/config.go | 34 +++++++++++++++---- generate/operation.go.tmpl | 10 ++++-- generate/testdata/InputObject.graphql.go | 4 +-- .../testdata/InterfaceNoFragments.graphql.go | 4 +-- generate/testdata/ListInput.graphql.go | 4 +-- generate/testdata/QueryWithAlias.graphql.go | 4 +-- .../testdata/QueryWithDoubleAlias.graphql.go | 4 +-- generate/testdata/QueryWithEnums.graphql.go | 4 +-- generate/testdata/QueryWithSlices.graphql.go | 4 +-- generate/testdata/QueryWithStructs.graphql.go | 4 +-- generate/testdata/SimpleInput.graphql.go | 4 +-- generate/testdata/SimpleQuery.graphql.go | 4 +-- generate/testdata/TypeName.graphql.go | 4 +-- generate/testdata/UnionNoFragments.graphql.go | 4 +-- generate/testdata/UsesEnumTwice.graphql.go | 4 +-- generate/testdata/unexported.graphql.go | 4 +-- generate/unmarshal.go | 1 + graphql/client.go | 4 ++- 19 files changed, 56 insertions(+), 51 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 81b9dff..d94e2db 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -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). diff --git a/generate/config.go b/generate/config.go index 441b814..ebcc4ab 100644 --- a/generate/config.go +++ b/generate/config.go @@ -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 != "" { diff --git a/generate/operation.go.tmpl b/generate/operation.go.tmpl index 13c5f03..23b534e 100644 --- a/generate/operation.go.tmpl +++ b/generate/operation.go.tmpl @@ -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}} diff --git a/generate/testdata/InputObject.graphql.go b/generate/testdata/InputObject.graphql.go index 3d8e60f..c7a6bfe 100644 --- a/generate/testdata/InputObject.graphql.go +++ b/generate/testdata/InputObject.graphql.go @@ -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 diff --git a/generate/testdata/InterfaceNoFragments.graphql.go b/generate/testdata/InterfaceNoFragments.graphql.go index 5315af4..393c944 100644 --- a/generate/testdata/InterfaceNoFragments.graphql.go +++ b/generate/testdata/InterfaceNoFragments.graphql.go @@ -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 diff --git a/generate/testdata/ListInput.graphql.go b/generate/testdata/ListInput.graphql.go index 96db5e9..b0d7722 100644 --- a/generate/testdata/ListInput.graphql.go +++ b/generate/testdata/ListInput.graphql.go @@ -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 diff --git a/generate/testdata/QueryWithAlias.graphql.go b/generate/testdata/QueryWithAlias.graphql.go index 3fef666..bceff06 100644 --- a/generate/testdata/QueryWithAlias.graphql.go +++ b/generate/testdata/QueryWithAlias.graphql.go @@ -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 diff --git a/generate/testdata/QueryWithDoubleAlias.graphql.go b/generate/testdata/QueryWithDoubleAlias.graphql.go index 6ca73cd..aa13030 100644 --- a/generate/testdata/QueryWithDoubleAlias.graphql.go +++ b/generate/testdata/QueryWithDoubleAlias.graphql.go @@ -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 diff --git a/generate/testdata/QueryWithEnums.graphql.go b/generate/testdata/QueryWithEnums.graphql.go index edabe15..c3828c3 100644 --- a/generate/testdata/QueryWithEnums.graphql.go +++ b/generate/testdata/QueryWithEnums.graphql.go @@ -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 diff --git a/generate/testdata/QueryWithSlices.graphql.go b/generate/testdata/QueryWithSlices.graphql.go index b7a8f6e..562a16c 100644 --- a/generate/testdata/QueryWithSlices.graphql.go +++ b/generate/testdata/QueryWithSlices.graphql.go @@ -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 diff --git a/generate/testdata/QueryWithStructs.graphql.go b/generate/testdata/QueryWithStructs.graphql.go index 921620c..c8d40c3 100644 --- a/generate/testdata/QueryWithStructs.graphql.go +++ b/generate/testdata/QueryWithStructs.graphql.go @@ -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 { diff --git a/generate/testdata/SimpleInput.graphql.go b/generate/testdata/SimpleInput.graphql.go index 453edbc..93c9942 100644 --- a/generate/testdata/SimpleInput.graphql.go +++ b/generate/testdata/SimpleInput.graphql.go @@ -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 diff --git a/generate/testdata/SimpleQuery.graphql.go b/generate/testdata/SimpleQuery.graphql.go index 7a2c617..06b6e57 100644 --- a/generate/testdata/SimpleQuery.graphql.go +++ b/generate/testdata/SimpleQuery.graphql.go @@ -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 diff --git a/generate/testdata/TypeName.graphql.go b/generate/testdata/TypeName.graphql.go index 8fdb82a..19823c0 100644 --- a/generate/testdata/TypeName.graphql.go +++ b/generate/testdata/TypeName.graphql.go @@ -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 diff --git a/generate/testdata/UnionNoFragments.graphql.go b/generate/testdata/UnionNoFragments.graphql.go index 5bcd2d6..53ad21a 100644 --- a/generate/testdata/UnionNoFragments.graphql.go +++ b/generate/testdata/UnionNoFragments.graphql.go @@ -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 diff --git a/generate/testdata/UsesEnumTwice.graphql.go b/generate/testdata/UsesEnumTwice.graphql.go index 64ead5c..3a99d93 100644 --- a/generate/testdata/UsesEnumTwice.graphql.go +++ b/generate/testdata/UsesEnumTwice.graphql.go @@ -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 diff --git a/generate/testdata/unexported.graphql.go b/generate/testdata/unexported.graphql.go index 3d6e0c1..1f3ff29 100644 --- a/generate/testdata/unexported.graphql.go +++ b/generate/testdata/unexported.graphql.go @@ -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 diff --git a/generate/unmarshal.go b/generate/unmarshal.go index 4d1a246..872ef67 100644 --- a/generate/unmarshal.go +++ b/generate/unmarshal.go @@ -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) } diff --git a/graphql/client.go b/graphql/client.go index 9e7d1db..ad707bc 100644 --- a/graphql/client.go +++ b/graphql/client.go @@ -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