Repository: Khan/genqlient
Pull request #184 (2022-03-29 14:26:04)

Adding GraphQL Extensions
This enables accessing the Extensions field, as defined in the response
format: https://spec.graphql.org/October2021/#sec-Response-Format

Extensions can be enabled using configuration option use_extensions.
This will change the return parameters of the generated client
functions. Making it a breaking change if enabled.

Since extensions are untyped as defined in the spec, the Client will
return an interface of type map[string]interface{}.

Issue: https://github.com/Khan/genqlient/issues/183


I have:
- [X] Written a clear PR title and description (above)
- [X] Signed the [Khan Academy CLA](https://www.khanacademy.org/r/cla)
- [X] Added tests covering my changes, if applicable
- [X] Included a link to the issue fixed, if applicable
- [X] Included documentation, for new features
- [x] Added an entry to the changelog


benjaminjkraft: Great, thanks for the changes and for the contribution!  I put in a few tiny tweaks to the documentation, which reminded me that this also fixes #19.

Patch:
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 0da5596..a86884e 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -23,10 +23,12 @@ When releasing a new version:
 ### Breaking changes:
 
 - genqlient now requires Go 1.16 or higher.
+- The [`graphql.Client`](https://pkg.go.dev/github.com/Khan/genqlient/graphql#Client) interface now accepts two structs for the request and response, to allow future expansion, rather than several individual arguments.  Clients implementing the interface themselves will need to change the signature; clients who simply call `graphql.NewClient` are unaffected.
 
 ### New features:
 
 - genqlient can now run as a portable binary (i.e. without a local checkout of the repository or `go run`).
+- You can now enable `use_extensions` in the configuration file, to receive extensions returned by the GraphQL API server. Generated functions will return extensions as `map[string]interface{}`, if enabled.
 
 ### Bug fixes:
 
diff --git a/docs/genqlient.yaml b/docs/genqlient.yaml
index f68ff65..d30235b 100644
--- a/docs/genqlient.yaml
+++ b/docs/genqlient.yaml
@@ -87,6 +87,16 @@ client_getter: "github.com/you/yourpkg.GetClient"
 # Defaults to false.
 use_struct_references: boolean
 
+# If set, generated code will have a third return parameter of type 
+# map[string]interface{}. This will contain the optional values
+# of the Extensions field send from Servers.
+# ref.: https://spec.graphql.org/October2021/#sec-Response-Format
+#
+# This can be useful for extending the GraphQL Protocol.
+#
+# Defaults to false.
+use_extensions: boolean
+
 
 # A map from GraphQL type name to Go fully-qualified type name to override
 # the Go type genqlient will use for this GraphQL type.
diff --git a/example/generated.go b/example/generated.go
index 85b041e..72ce68e 100644
--- a/example/generated.go
+++ b/example/generated.go
@@ -75,16 +75,9 @@ func getUser(
 	client graphql.Client,
 	Login string,
 ) (*getUserResponse, error) {
-	__input := __getUserInput{
-		Login: Login,
-	}
-	var err error
-
-	var retval getUserResponse
-	err = client.MakeRequest(
-		ctx,
-		"getUser",
-		`
+	req := &graphql.Request{
+		OpName: "getUser",
+		Query: `
 query getUser ($Login: String!) {
 	user(login: $Login) {
 		theirName: name
@@ -92,23 +85,31 @@ query getUser ($Login: String!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__getUserInput{
+			Login: Login,
+		},
+	}
+	var err error
+
+	var data getUserResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
 func getViewer(
 	ctx context.Context,
 	client graphql.Client,
 ) (*getViewerResponse, error) {
-	var err error
-
-	var retval getViewerResponse
-	err = client.MakeRequest(
-		ctx,
-		"getViewer",
-		`
+	req := &graphql.Request{
+		OpName: "getViewer",
+		Query: `
 query getViewer {
 	viewer {
 		MyName: name
@@ -116,8 +117,17 @@ query getViewer {
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data getViewerResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
diff --git a/example/genqlient.yaml b/example/genqlient.yaml
index 74f0533..11cd034 100644
--- a/example/genqlient.yaml
+++ b/example/genqlient.yaml
@@ -2,7 +2,6 @@ schema: schema.graphql
 operations:
 - genqlient.graphql
 generated: generated.go
-
 # needed since it doesn't match the directory name:
 package: main
 
diff --git a/generate/config.go b/generate/config.go
index 21fde5d..5f019c3 100644
--- a/generate/config.go
+++ b/generate/config.go
@@ -27,6 +27,7 @@ type Config struct {
 	ClientGetter     string                  `yaml:"client_getter"`
 	Bindings         map[string]*TypeBinding `yaml:"bindings"`
 	StructReferences bool                    `yaml:"use_struct_references"`
+	Extensions       bool                    `yaml:"use_extensions"`
 
 	// Set to true to use features that aren't fully ready to use.
 	//
diff --git a/generate/operation.go.tmpl b/generate/operation.go.tmpl
index 47a0c93..b379e9f 100644
--- a/generate/operation.go.tmpl
+++ b/generate/operation.go.tmpl
@@ -12,34 +12,35 @@ func {{.Name}}(
     {{.GraphQLName}} {{.GoType.Reference}},
     {{end -}}
     {{end -}}
-) (*{{.ResponseName}}, error) {
-    {{- if .Input -}}
-    {{/* We need to avoid conflicting with any of the function's argument names
-         which are derived from the GraphQL argument names; notably `input` is
-         a common one.  So we use a name that's not legal in GraphQL, namely
-         one starting with a double-underscore. */ -}}
-    __input := {{.Input.GoName}}{
+) (*{{.ResponseName}}, {{if .Config.Extensions -}}map[string]interface{},{{end}} error) {
+    req := &graphql.Request{
+        OpName: "{{.Name}}",
+        Query:  `{{.Body}}`,
+    {{if .Input -}}
+        Variables: &{{.Input.GoName}}{
         {{range .Input.Fields -}}
         {{.GoName}}: {{.GraphQLName}},
         {{end -}}
-    }
+        },
     {{end -}}
-
+    }
     var err error
     {{if .Config.ClientGetter -}}
-    client, err := {{ref .Config.ClientGetter}}({{if ne .Config.ContextType "-"}}ctx{{else}}{{end}})
+    var client graphql.Client
+
+    client, err = {{ref .Config.ClientGetter}}({{if ne .Config.ContextType "-"}}ctx{{else}}{{end}})
     if err != nil {
-        return nil, err
+        return nil, {{if .Config.Extensions -}}nil,{{end -}} err
     }
     {{end}}
+    var data {{.ResponseName}}
+    resp := &graphql.Response{Data: &data}
 
-	var retval {{.ResponseName}}
     err = client.MakeRequest(
         {{if ne .Config.ContextType "-"}}ctx{{else}}nil{{end}},
-        "{{.Name}}",
-        `{{.Body}}`,
-        &retval,
-        {{if .Input}}&__input{{else}}nil{{end}},
+        req,
+        resp,
     )
-    return &retval, err
+	
+    return &data, {{if .Config.Extensions -}}resp.Extensions,{{end -}} err
 }
diff --git a/graphql/client.go b/graphql/client.go
index 832bb92..4715470 100644
--- a/graphql/client.go
+++ b/graphql/client.go
@@ -13,9 +13,6 @@ import (
 
 // Client is the interface that the generated code calls into to actually make
 // requests.
-//
-// Unstable: This interface is likely to change before v1.0, see #19.  Creating
-// a client with NewClient will remain the same.
 type Client interface {
 	// MakeRequest must make a request to the client's GraphQL API.
 	//
@@ -23,26 +20,20 @@ type Client interface {
 	// is disabled in the genqlient settings, this will be set to
 	// context.Background().
 	//
-	// query is the literal string representing the GraphQL query, e.g.
-	// `query myQuery { myField }`.  variables contains a JSON-marshalable
-	// value containing the variables to be sent along with the query,
-	// or may be nil if there are none.  Typically, GraphQL APIs will
-	// accept a JSON payload of the form
-	//	{"query": "query myQuery { ... }", "variables": {...}}`
-	// but MakeRequest may use some other transport, handle extensions, or set
-	// other parameters, if it wishes.
+	// req contains the data to be sent to the GraphQL server.  Typically GraphQL
+	// APIs will expect it to simply be marshalled as JSON, but MakeRequest may
+	// customize this.
 	//
-	// retval is a pointer to the struct representing the query result, e.g.
-	// new(myQueryResponse).  Typically, GraphQL APIs will return a JSON
-	// payload of the form
-	//	{"data": {...}, "errors": {...}}
-	// and retval is designed so that `data` will json-unmarshal into `retval`.
-	// (Errors are returned.) But again, MakeRequest may customize this.
+	// resp is the Response object into which the server's response will be
+	// unmarshalled. Typically GraphQL APIs will return JSON which can be
+	// unmarshalled directly into resp, but MakeRequest can customize it.
+	// If the response contains an error, this must also be returned by
+	// MakeRequest.  The field resp.Data will be prepopulated with a pointer
+	// to an empty struct of the correct generated type (e.g. MyQueryResponse).
 	MakeRequest(
 		ctx context.Context,
-		opName string,
-		query string,
-		retval, input interface{},
+		req *Request,
+		resp *Response,
 	) error
 }
 
@@ -75,65 +66,79 @@ type Doer interface {
 	Do(*http.Request) (*http.Response, error)
 }
 
-type payload struct {
-	Query     string      `json:"query"`
+// Request contains all the values required to build queries executed by
+// the graphql.Client.
+//
+// Typically, GraphQL APIs will accept a JSON payload of the form
+//	{"query": "query myQuery { ... }", "variables": {...}}`
+// and Request marshals to this format.  However, MakeRequest may
+// marshal the data in some other way desired by the backend.
+type Request struct {
+	// The literal string representing the GraphQL query, e.g.
+	// `query myQuery { myField }`.
+	Query string `json:"query"`
+	// A JSON-marshalable value containing the variables to be sent
+	// along with the query, or nil if there are none.
 	Variables interface{} `json:"variables,omitempty"`
-	// OpName is only required if there are multiple queries in the document,
-	// but we set it unconditionally, because that's easier.
+	// The GraphQL operation name. The server typically doesn't
+	// require this unless there are multiple queries in the
+	// document, but genqlient sets it unconditionally anyway.
 	OpName string `json:"operationName"`
 }
 
-type response struct {
-	Data   interface{}   `json:"data"`
-	Errors gqlerror.List `json:"errors"`
+// Response that contains data returned by the GraphQL API.
+//
+// Typically, GraphQL APIs will return a JSON payload of the form
+//	{"data": {...}, "errors": {...}}
+// It may additionally contain a key named "extensions", that
+// might hold GraphQL protocol extensions. Extensions and Errors
+// are optional, depending on the values returned by the server.
+type Response struct {
+	Data       interface{}            `json:"data"`
+	Extensions map[string]interface{} `json:"extensions,omitempty"`
+	Errors     gqlerror.List          `json:"errors,omitempty"`
 }
 
-func (c *client) MakeRequest(ctx context.Context, opName string, query string, retval interface{}, variables interface{}) error {
-	body, err := json.Marshal(payload{
-		Query:     query,
-		Variables: variables,
-		OpName:    opName,
-	})
+func (c *client) MakeRequest(ctx context.Context, req *Request, resp *Response) error {
+	body, err := json.Marshal(req)
 	if err != nil {
 		return err
 	}
 
-	req, err := http.NewRequest(
+	httpReq, err := http.NewRequest(
 		c.method,
 		c.endpoint,
 		bytes.NewReader(body))
 	if err != nil {
 		return err
 	}
-	req.Header.Set("Content-Type", "application/json")
+	httpReq.Header.Set("Content-Type", "application/json")
 
 	if ctx != nil {
-		req = req.WithContext(ctx)
+		httpReq = httpReq.WithContext(ctx)
 	}
-	resp, err := c.httpClient.Do(req)
+
+	httpResp, err := c.httpClient.Do(httpReq)
 	if err != nil {
 		return err
 	}
-	defer resp.Body.Close()
+	defer httpResp.Body.Close()
 
-	if resp.StatusCode != http.StatusOK {
+	if httpResp.StatusCode != http.StatusOK {
 		var respBody []byte
-		respBody, err = io.ReadAll(resp.Body)
+		respBody, err = io.ReadAll(httpResp.Body)
 		if err != nil {
 			respBody = []byte(fmt.Sprintf("<unreadable: %v>", err))
 		}
-		return fmt.Errorf("returned error %v: %s", resp.Status, respBody)
+		return fmt.Errorf("returned error %v: %s", httpResp.Status, respBody)
 	}
 
-	var dataAndErrors response
-	dataAndErrors.Data = retval
-	err = json.NewDecoder(resp.Body).Decode(&dataAndErrors)
+	err = json.NewDecoder(httpResp.Body).Decode(resp)
 	if err != nil {
 		return err
 	}
-
-	if len(dataAndErrors.Errors) > 0 {
-		return dataAndErrors.Errors
+	if len(resp.Errors) > 0 {
+		return resp.Errors
 	}
 	return nil
 }
diff --git a/internal/integration/generated.go b/internal/integration/generated.go
index 086e78f..8ebe975 100644
--- a/internal/integration/generated.go
+++ b/internal/integration/generated.go
@@ -2995,6 +2995,30 @@ func (v *queryWithVariablesUser) GetName() string { return v.Name }
 // GetLuckyNumber returns queryWithVariablesUser.LuckyNumber, and is useful for accessing the field via an interface.
 func (v *queryWithVariablesUser) GetLuckyNumber() int { return v.LuckyNumber }
 
+// simpleQueryExtMeUser includes the requested fields of the GraphQL type User.
+type simpleQueryExtMeUser struct {
+	Id          string `json:"id"`
+	Name        string `json:"name"`
+	LuckyNumber int    `json:"luckyNumber"`
+}
+
+// GetId returns simpleQueryExtMeUser.Id, and is useful for accessing the field via an interface.
+func (v *simpleQueryExtMeUser) GetId() string { return v.Id }
+
+// GetName returns simpleQueryExtMeUser.Name, and is useful for accessing the field via an interface.
+func (v *simpleQueryExtMeUser) GetName() string { return v.Name }
+
+// GetLuckyNumber returns simpleQueryExtMeUser.LuckyNumber, and is useful for accessing the field via an interface.
+func (v *simpleQueryExtMeUser) GetLuckyNumber() int { return v.LuckyNumber }
+
+// simpleQueryExtResponse is returned by simpleQueryExt on success.
+type simpleQueryExtResponse struct {
+	Me simpleQueryExtMeUser `json:"me"`
+}
+
+// GetMe returns simpleQueryExtResponse.Me, and is useful for accessing the field via an interface.
+func (v *simpleQueryExtResponse) GetMe() simpleQueryExtMeUser { return v.Me }
+
 // simpleQueryMeUser includes the requested fields of the GraphQL type User.
 type simpleQueryMeUser struct {
 	Id          string `json:"id"`
@@ -3022,14 +3046,10 @@ func (v *simpleQueryResponse) GetMe() simpleQueryMeUser { return v.Me }
 func failingQuery(
 	ctx context.Context,
 	client graphql.Client,
-) (*failingQueryResponse, error) {
-	var err error
-
-	var retval failingQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"failingQuery",
-		`
+) (*failingQueryResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "failingQuery",
+		Query: `
 query failingQuery {
 	fail
 	me {
@@ -3037,27 +3057,29 @@ query failingQuery {
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data failingQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithCustomMarshal(
 	ctx context.Context,
 	client graphql.Client,
 	date time.Time,
-) (*queryWithCustomMarshalResponse, error) {
-	__input := __queryWithCustomMarshalInput{
-		Date: date,
-	}
-	var err error
-
-	var retval queryWithCustomMarshalResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithCustomMarshal",
-		`
+) (*queryWithCustomMarshalResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithCustomMarshal",
+		Query: `
 query queryWithCustomMarshal ($date: Date!) {
 	usersBornOn(date: $date) {
 		id
@@ -3066,10 +3088,22 @@ query queryWithCustomMarshal ($date: Date!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithCustomMarshalInput{
+			Date: date,
+		},
+	}
+	var err error
+
+	var data queryWithCustomMarshalResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithCustomMarshalOptional(
@@ -3077,18 +3111,10 @@ func queryWithCustomMarshalOptional(
 	client graphql.Client,
 	date *time.Time,
 	id *string,
-) (*queryWithCustomMarshalOptionalResponse, error) {
-	__input := __queryWithCustomMarshalOptionalInput{
-		Date: date,
-		Id:   id,
-	}
-	var err error
-
-	var retval queryWithCustomMarshalOptionalResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithCustomMarshalOptional",
-		`
+) (*queryWithCustomMarshalOptionalResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithCustomMarshalOptional",
+		Query: `
 query queryWithCustomMarshalOptional ($date: Date, $id: ID) {
 	userSearch(birthdate: $date, id: $id) {
 		id
@@ -3097,27 +3123,33 @@ query queryWithCustomMarshalOptional ($date: Date, $id: ID) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithCustomMarshalOptionalInput{
+			Date: date,
+			Id:   id,
+		},
+	}
+	var err error
+
+	var data queryWithCustomMarshalOptionalResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithCustomMarshalSlice(
 	ctx context.Context,
 	client graphql.Client,
 	dates []time.Time,
-) (*queryWithCustomMarshalSliceResponse, error) {
-	__input := __queryWithCustomMarshalSliceInput{
-		Dates: dates,
-	}
-	var err error
-
-	var retval queryWithCustomMarshalSliceResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithCustomMarshalSlice",
-		`
+) (*queryWithCustomMarshalSliceResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithCustomMarshalSlice",
+		Query: `
 query queryWithCustomMarshalSlice ($dates: [Date!]!) {
 	usersBornOnDates(dates: $dates) {
 		id
@@ -3126,27 +3158,32 @@ query queryWithCustomMarshalSlice ($dates: [Date!]!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithCustomMarshalSliceInput{
+			Dates: dates,
+		},
+	}
+	var err error
+
+	var data queryWithCustomMarshalSliceResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithFlatten(
 	ctx context.Context,
 	client graphql.Client,
 	ids []string,
-) (*QueryFragment, error) {
-	__input := __queryWithFlattenInput{
-		Ids: ids,
-	}
-	var err error
-
-	var retval QueryFragment
-	err = client.MakeRequest(
-		ctx,
-		"queryWithFlatten",
-		`
+) (*QueryFragment, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithFlatten",
+		Query: `
 query queryWithFlatten ($ids: [ID!]!) {
 	... QueryFragment
 }
@@ -3189,27 +3226,32 @@ fragment FriendsFields on User {
 	name
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithFlattenInput{
+			Ids: ids,
+		},
+	}
+	var err error
+
+	var data QueryFragment
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithFragments(
 	ctx context.Context,
 	client graphql.Client,
 	ids []string,
-) (*queryWithFragmentsResponse, error) {
-	__input := __queryWithFragmentsInput{
-		Ids: ids,
-	}
-	var err error
-
-	var retval queryWithFragmentsResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithFragments",
-		`
+) (*queryWithFragmentsResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithFragments",
+		Query: `
 query queryWithFragments ($ids: [ID!]!) {
 	beings(ids: $ids) {
 		__typename
@@ -3246,27 +3288,32 @@ query queryWithFragments ($ids: [ID!]!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithFragmentsInput{
+			Ids: ids,
+		},
+	}
+	var err error
+
+	var data queryWithFragmentsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithInterfaceListField(
 	ctx context.Context,
 	client graphql.Client,
 	ids []string,
-) (*queryWithInterfaceListFieldResponse, error) {
-	__input := __queryWithInterfaceListFieldInput{
-		Ids: ids,
-	}
-	var err error
-
-	var retval queryWithInterfaceListFieldResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithInterfaceListField",
-		`
+) (*queryWithInterfaceListFieldResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithInterfaceListField",
+		Query: `
 query queryWithInterfaceListField ($ids: [ID!]!) {
 	beings(ids: $ids) {
 		__typename
@@ -3275,27 +3322,32 @@ query queryWithInterfaceListField ($ids: [ID!]!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithInterfaceListFieldInput{
+			Ids: ids,
+		},
+	}
+	var err error
+
+	var data queryWithInterfaceListFieldResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithInterfaceListPointerField(
 	ctx context.Context,
 	client graphql.Client,
 	ids []string,
-) (*queryWithInterfaceListPointerFieldResponse, error) {
-	__input := __queryWithInterfaceListPointerFieldInput{
-		Ids: ids,
-	}
-	var err error
-
-	var retval queryWithInterfaceListPointerFieldResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithInterfaceListPointerField",
-		`
+) (*queryWithInterfaceListPointerFieldResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithInterfaceListPointerField",
+		Query: `
 query queryWithInterfaceListPointerField ($ids: [ID!]!) {
 	beings(ids: $ids) {
 		__typename
@@ -3304,27 +3356,32 @@ query queryWithInterfaceListPointerField ($ids: [ID!]!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithInterfaceListPointerFieldInput{
+			Ids: ids,
+		},
+	}
+	var err error
+
+	var data queryWithInterfaceListPointerFieldResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithInterfaceNoFragments(
 	ctx context.Context,
 	client graphql.Client,
 	id string,
-) (*queryWithInterfaceNoFragmentsResponse, error) {
-	__input := __queryWithInterfaceNoFragmentsInput{
-		Id: id,
-	}
-	var err error
-
-	var retval queryWithInterfaceNoFragmentsResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithInterfaceNoFragments",
-		`
+) (*queryWithInterfaceNoFragmentsResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithInterfaceNoFragments",
+		Query: `
 query queryWithInterfaceNoFragments ($id: ID!) {
 	being(id: $id) {
 		__typename
@@ -3337,27 +3394,32 @@ query queryWithInterfaceNoFragments ($id: ID!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithInterfaceNoFragmentsInput{
+			Id: id,
+		},
+	}
+	var err error
+
+	var data queryWithInterfaceNoFragmentsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithNamedFragments(
 	ctx context.Context,
 	client graphql.Client,
 	ids []string,
-) (*queryWithNamedFragmentsResponse, error) {
-	__input := __queryWithNamedFragmentsInput{
-		Ids: ids,
-	}
-	var err error
-
-	var retval queryWithNamedFragmentsResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithNamedFragments",
-		`
+) (*queryWithNamedFragmentsResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithNamedFragments",
+		Query: `
 query queryWithNamedFragments ($ids: [ID!]!) {
 	beings(ids: $ids) {
 		__typename
@@ -3394,27 +3456,32 @@ fragment MoreUserFields on User {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithNamedFragmentsInput{
+			Ids: ids,
+		},
+	}
+	var err error
+
+	var data queryWithNamedFragmentsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithOmitempty(
 	ctx context.Context,
 	client graphql.Client,
 	id string,
-) (*queryWithOmitemptyResponse, error) {
-	__input := __queryWithOmitemptyInput{
-		Id: id,
-	}
-	var err error
-
-	var retval queryWithOmitemptyResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithOmitempty",
-		`
+) (*queryWithOmitemptyResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithOmitempty",
+		Query: `
 query queryWithOmitempty ($id: ID) {
 	user(id: $id) {
 		id
@@ -3423,27 +3490,32 @@ query queryWithOmitempty ($id: ID) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithOmitemptyInput{
+			Id: id,
+		},
+	}
+	var err error
+
+	var data queryWithOmitemptyResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func queryWithVariables(
 	ctx context.Context,
 	client graphql.Client,
 	id string,
-) (*queryWithVariablesResponse, error) {
-	__input := __queryWithVariablesInput{
-		Id: id,
-	}
-	var err error
-
-	var retval queryWithVariablesResponse
-	err = client.MakeRequest(
-		ctx,
-		"queryWithVariables",
-		`
+) (*queryWithVariablesResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "queryWithVariables",
+		Query: `
 query queryWithVariables ($id: ID!) {
 	user(id: $id) {
 		id
@@ -3452,24 +3524,62 @@ query queryWithVariables ($id: ID!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__queryWithVariablesInput{
+			Id: id,
+		},
+	}
+	var err error
+
+	var data queryWithVariablesResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
 
 func simpleQuery(
 	ctx context.Context,
 	client graphql.Client,
-) (*simpleQueryResponse, error) {
+) (*simpleQueryResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "simpleQuery",
+		Query: `
+query simpleQuery {
+	me {
+		id
+		name
+		luckyNumber
+	}
+}
+`,
+	}
 	var err error
 
-	var retval simpleQueryResponse
+	var data simpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
 	err = client.MakeRequest(
 		ctx,
-		"simpleQuery",
-		`
-query simpleQuery {
+		req,
+		resp,
+	)
+
+	return &data, resp.Extensions, err
+}
+
+func simpleQueryExt(
+	ctx context.Context,
+	client graphql.Client,
+) (*simpleQueryExtResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "simpleQueryExt",
+		Query: `
+query simpleQueryExt {
 	me {
 		id
 		name
@@ -3477,8 +3587,17 @@ query simpleQuery {
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data simpleQueryExtResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, resp.Extensions, err
 }
diff --git a/internal/integration/genqlient.yaml b/internal/integration/genqlient.yaml
index 50c2cf4..db6f988 100644
--- a/internal/integration/genqlient.yaml
+++ b/internal/integration/genqlient.yaml
@@ -2,6 +2,7 @@ schema: schema.graphql
 operations: "*_test.go"
 generated: generated.go
 allow_broken_features: true
+use_extensions: true
 bindings:
   Date:
     type: time.Time
diff --git a/internal/integration/roundtrip.go b/internal/integration/roundtrip.go
index 0fec83d..4653b18 100644
--- a/internal/integration/roundtrip.go
+++ b/internal/integration/roundtrip.go
@@ -88,16 +88,16 @@ func (c *roundtripClient) roundtripResponse(resp interface{}) {
 	assert.Equal(c.t, string(body), string(bodyAgain))
 }
 
-func (c *roundtripClient) MakeRequest(ctx context.Context, opName, query string, retval, variables interface{}) error {
+func (c *roundtripClient) MakeRequest(ctx context.Context, req *graphql.Request, resp *graphql.Response) error {
 	// TODO(benkraft): Also check the variables round-trip.  This is a bit less
 	// important since most of the code is the same (and input types are
 	// strictly simpler), and a bit hard to do because when asserting about
 	// structs we need to worry about things like equality of time.Time values.
-	err := c.wrapped.MakeRequest(ctx, opName, query, retval, variables)
+	err := c.wrapped.MakeRequest(ctx, req, resp)
 	if err != nil {
 		return err
 	}
-	c.roundtripResponse(retval)
+	c.roundtripResponse(resp.Data)
 	return nil
 }
 
diff --git a/internal/integration/server/gqlgen_exec.go b/internal/integration/server/gqlgen_exec.go
index 14a7607..d0e4fd9 100644
--- a/internal/integration/server/gqlgen_exec.go
+++ b/internal/integration/server/gqlgen_exec.go
@@ -531,21 +531,6 @@ func (ec *executionContext) field_Query_usersBornOn_args(ctx context.Context, ra
 	return args, nil
 }
 
-func (ec *executionContext) field___Field_args_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
-	var err error
-	args := map[string]interface{}{}
-	var arg0 *bool
-	if tmp, ok := rawArgs["includeDeprecated"]; ok {
-		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated"))
-		arg0, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
-		if err != nil {
-			return nil, err
-		}
-	}
-	args["includeDeprecated"] = arg0
-	return args, nil
-}
-
 func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
 	var err error
 	args := map[string]interface{}{}
@@ -1484,14 +1469,14 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field
 		Object:     "__Directive",
 		Field:      field,
 		Args:       nil,
-		IsMethod:   false,
+		IsMethod:   true,
 		IsResolver: false,
 	}
 
 	ctx = graphql.WithFieldContext(ctx, fc)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Description, nil
+		return obj.Description(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -1500,9 +1485,9 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(string)
+	res := resTmp.(*string)
 	fc.Result = res
-	return ec.marshalOString2string(ctx, field.Selections, res)
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
@@ -1656,14 +1641,14 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field
 		Object:     "__EnumValue",
 		Field:      field,
 		Args:       nil,
-		IsMethod:   false,
+		IsMethod:   true,
 		IsResolver: false,
 	}
 
 	ctx = graphql.WithFieldContext(ctx, fc)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Description, nil
+		return obj.Description(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -1672,9 +1657,9 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(string)
+	res := resTmp.(*string)
 	fc.Result = res
-	return ec.marshalOString2string(ctx, field.Selections, res)
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {
@@ -1790,14 +1775,14 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap
 		Object:     "__Field",
 		Field:      field,
 		Args:       nil,
-		IsMethod:   false,
+		IsMethod:   true,
 		IsResolver: false,
 	}
 
 	ctx = graphql.WithFieldContext(ctx, fc)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Description, nil
+		return obj.Description(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -1806,9 +1791,9 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(string)
+	res := resTmp.(*string)
 	fc.Result = res
-	return ec.marshalOString2string(ctx, field.Selections, res)
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
@@ -1827,13 +1812,6 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col
 	}
 
 	ctx = graphql.WithFieldContext(ctx, fc)
-	rawArgs := field.ArgumentMap(ec.Variables)
-	args, err := ec.field___Field_args_args(ctx, rawArgs)
-	if err != nil {
-		ec.Error(ctx, err)
-		return graphql.Null
-	}
-	fc.Args = args
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
 		return obj.Args, nil
@@ -2001,14 +1979,14 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field
 		Object:     "__InputValue",
 		Field:      field,
 		Args:       nil,
-		IsMethod:   false,
+		IsMethod:   true,
 		IsResolver: false,
 	}
 
 	ctx = graphql.WithFieldContext(ctx, fc)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Description, nil
+		return obj.Description(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2017,9 +1995,9 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(string)
+	res := resTmp.(*string)
 	fc.Result = res
-	return ec.marshalOString2string(ctx, field.Selections, res)
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {
@@ -2089,6 +2067,38 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel
 	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
+func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	fc := &graphql.FieldContext{
+		Object:     "__Schema",
+		Field:      field,
+		Args:       nil,
+		IsMethod:   true,
+		IsResolver: false,
+	}
+
+	ctx = graphql.WithFieldContext(ctx, fc)
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.Description(), nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*string)
+	fc.Result = res
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
 func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
 	defer func() {
 		if r := recover(); r != nil {
@@ -2352,9 +2362,9 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(string)
+	res := resTmp.(*string)
 	fc.Result = res
-	return ec.marshalOString2string(ctx, field.Selections, res)
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
@@ -2563,6 +2573,38 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
 	return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
 }
 
+func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+	defer func() {
+		if r := recover(); r != nil {
+			ec.Error(ctx, ec.Recover(ctx, r))
+			ret = graphql.Null
+		}
+	}()
+	fc := &graphql.FieldContext{
+		Object:     "__Type",
+		Field:      field,
+		Args:       nil,
+		IsMethod:   true,
+		IsResolver: false,
+	}
+
+	ctx = graphql.WithFieldContext(ctx, fc)
+	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+		ctx = rctx // use context from middleware stack in children
+		return obj.SpecifiedByURL(), nil
+	})
+	if err != nil {
+		ec.Error(ctx, err)
+		return graphql.Null
+	}
+	if resTmp == nil {
+		return graphql.Null
+	}
+	res := resTmp.(*string)
+	fc.Result = res
+	return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
 // endregion **************************** field.gotpl *****************************
 
 // region    **************************** input.gotpl *****************************
@@ -2618,7 +2660,6 @@ var animalImplementors = []string{"Animal", "Being"}
 
 func (ec *executionContext) _Animal(ctx context.Context, sel ast.SelectionSet, obj *Animal) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, animalImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2626,24 +2667,49 @@ func (ec *executionContext) _Animal(ctx context.Context, sel ast.SelectionSet, o
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("Animal")
 		case "id":
-			out.Values[i] = ec._Animal_id(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Animal_id(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "name":
-			out.Values[i] = ec._Animal_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Animal_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "species":
-			out.Values[i] = ec._Animal_species(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Animal_species(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "owner":
-			out.Values[i] = ec._Animal_owner(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Animal_owner(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "hair":
-			out.Values[i] = ec._Animal_hair(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Animal_hair(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -2659,7 +2725,6 @@ var beingsHairImplementors = []string{"BeingsHair"}
 
 func (ec *executionContext) _BeingsHair(ctx context.Context, sel ast.SelectionSet, obj *BeingsHair) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, beingsHairImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2667,7 +2732,12 @@ func (ec *executionContext) _BeingsHair(ctx context.Context, sel ast.SelectionSe
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("BeingsHair")
 		case "hasHair":
-			out.Values[i] = ec._BeingsHair_hasHair(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._BeingsHair_hasHair(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
@@ -2686,7 +2756,6 @@ var hairImplementors = []string{"Hair"}
 
 func (ec *executionContext) _Hair(ctx context.Context, sel ast.SelectionSet, obj *Hair) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, hairImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2694,7 +2763,12 @@ func (ec *executionContext) _Hair(ctx context.Context, sel ast.SelectionSet, obj
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("Hair")
 		case "color":
-			out.Values[i] = ec._Hair_color(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Hair_color(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -2710,7 +2784,6 @@ var queryImplementors = []string{"Query"}
 
 func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors)
-
 	ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
 		Object: "Query",
 	})
@@ -2718,12 +2791,18 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
+		innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
+			Object: field.Name,
+			Field:  field,
+		})
+
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("Query")
 		case "me":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2731,10 +2810,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 				}()
 				res = ec._Query_me(ctx, field)
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "user":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2742,10 +2830,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 				}()
 				res = ec._Query_user(ctx, field)
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "being":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2753,10 +2850,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 				}()
 				res = ec._Query_being(ctx, field)
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "beings":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2767,10 +2873,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 					atomic.AddUint32(&invalids, 1)
 				}
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "lotteryWinner":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2778,10 +2893,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 				}()
 				res = ec._Query_lotteryWinner(ctx, field)
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "usersBornOn":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2792,10 +2916,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 					atomic.AddUint32(&invalids, 1)
 				}
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "usersBornOnDates":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2806,10 +2939,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 					atomic.AddUint32(&invalids, 1)
 				}
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "userSearch":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2817,10 +2959,19 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 				}()
 				res = ec._Query_userSearch(ctx, field)
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "fail":
 			field := field
-			out.Concurrently(i, func() (res graphql.Marshaler) {
+
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
 				defer func() {
 					if r := recover(); r != nil {
 						ec.Error(ctx, ec.Recover(ctx, r))
@@ -2828,11 +2979,29 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
 				}()
 				res = ec._Query_fail(ctx, field)
 				return res
+			}
+
+			rrm := func(ctx context.Context) graphql.Marshaler {
+				return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
+			}
+
+			out.Concurrently(i, func() graphql.Marshaler {
+				return rrm(innerCtx)
 			})
 		case "__type":
-			out.Values[i] = ec._Query___type(ctx, field)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Query___type(ctx, field)
+			}
+
+			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc)
+
 		case "__schema":
-			out.Values[i] = ec._Query___schema(ctx, field)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._Query___schema(ctx, field)
+			}
+
+			out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -2848,7 +3017,6 @@ var userImplementors = []string{"User", "Being", "Lucky"}
 
 func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *User) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2856,23 +3024,53 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("User")
 		case "id":
-			out.Values[i] = ec._User_id(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._User_id(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "name":
-			out.Values[i] = ec._User_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._User_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "luckyNumber":
-			out.Values[i] = ec._User_luckyNumber(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._User_luckyNumber(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "hair":
-			out.Values[i] = ec._User_hair(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._User_hair(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "birthdate":
-			out.Values[i] = ec._User_birthdate(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._User_birthdate(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "friends":
-			out.Values[i] = ec._User_friends(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec._User_friends(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
@@ -2891,7 +3089,6 @@ var __DirectiveImplementors = []string{"__Directive"}
 
 func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2899,24 +3096,49 @@ func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionS
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("__Directive")
 		case "name":
-			out.Values[i] = ec.___Directive_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Directive_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "description":
-			out.Values[i] = ec.___Directive_description(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Directive_description(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "locations":
-			out.Values[i] = ec.___Directive_locations(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Directive_locations(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "args":
-			out.Values[i] = ec.___Directive_args(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Directive_args(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "isRepeatable":
-			out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Directive_isRepeatable(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
@@ -2935,7 +3157,6 @@ var __EnumValueImplementors = []string{"__EnumValue"}
 
 func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2943,19 +3164,39 @@ func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionS
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("__EnumValue")
 		case "name":
-			out.Values[i] = ec.___EnumValue_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___EnumValue_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "description":
-			out.Values[i] = ec.___EnumValue_description(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___EnumValue_description(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "isDeprecated":
-			out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___EnumValue_isDeprecated(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "deprecationReason":
-			out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___EnumValue_deprecationReason(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -2971,7 +3212,6 @@ var __FieldImplementors = []string{"__Field"}
 
 func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -2979,29 +3219,59 @@ func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet,
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("__Field")
 		case "name":
-			out.Values[i] = ec.___Field_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Field_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "description":
-			out.Values[i] = ec.___Field_description(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Field_description(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "args":
-			out.Values[i] = ec.___Field_args(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Field_args(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "type":
-			out.Values[i] = ec.___Field_type(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Field_type(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "isDeprecated":
-			out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Field_isDeprecated(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "deprecationReason":
-			out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Field_deprecationReason(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -3017,7 +3287,6 @@ var __InputValueImplementors = []string{"__InputValue"}
 
 func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -3025,19 +3294,39 @@ func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.Selection
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("__InputValue")
 		case "name":
-			out.Values[i] = ec.___InputValue_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___InputValue_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "description":
-			out.Values[i] = ec.___InputValue_description(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___InputValue_description(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "type":
-			out.Values[i] = ec.___InputValue_type(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___InputValue_type(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "defaultValue":
-			out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___InputValue_defaultValue(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -3053,29 +3342,60 @@ var __SchemaImplementors = []string{"__Schema"}
 
 func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("__Schema")
+		case "description":
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Schema_description(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "types":
-			out.Values[i] = ec.___Schema_types(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Schema_types(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "queryType":
-			out.Values[i] = ec.___Schema_queryType(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Schema_queryType(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "mutationType":
-			out.Values[i] = ec.___Schema_mutationType(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Schema_mutationType(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "subscriptionType":
-			out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Schema_subscriptionType(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "directives":
-			out.Values[i] = ec.___Schema_directives(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Schema_directives(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
@@ -3094,7 +3414,6 @@ var __TypeImplementors = []string{"__Type"}
 
 func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler {
 	fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors)
-
 	out := graphql.NewFieldSet(fields)
 	var invalids uint32
 	for i, field := range fields {
@@ -3102,26 +3421,78 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("__Type")
 		case "kind":
-			out.Values[i] = ec.___Type_kind(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_kind(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 			if out.Values[i] == graphql.Null {
 				invalids++
 			}
 		case "name":
-			out.Values[i] = ec.___Type_name(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_name(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "description":
-			out.Values[i] = ec.___Type_description(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_description(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "fields":
-			out.Values[i] = ec.___Type_fields(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_fields(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "interfaces":
-			out.Values[i] = ec.___Type_interfaces(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_interfaces(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "possibleTypes":
-			out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_possibleTypes(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "enumValues":
-			out.Values[i] = ec.___Type_enumValues(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_enumValues(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "inputFields":
-			out.Values[i] = ec.___Type_inputFields(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_inputFields(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		case "ofType":
-			out.Values[i] = ec.___Type_ofType(ctx, field, obj)
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_ofType(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
+		case "specifiedByURL":
+			innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
+				return ec.___Type_specifiedByURL(ctx, field, obj)
+			}
+
+			out.Values[i] = innerFunc(ctx)
+
 		default:
 			panic("unknown field " + strconv.Quote(field.Name))
 		}
@@ -3208,11 +3579,7 @@ func (ec *executionContext) marshalNDate2string(ctx context.Context, sel ast.Sel
 func (ec *executionContext) unmarshalNDate2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) {
 	var vSlice []interface{}
 	if v != nil {
-		if tmp1, ok := v.([]interface{}); ok {
-			vSlice = tmp1
-		} else {
-			vSlice = []interface{}{v}
-		}
+		vSlice = graphql.CoerceList(v)
 	}
 	var err error
 	res := make([]string, len(vSlice))
@@ -3259,11 +3626,7 @@ func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.Selec
 func (ec *executionContext) unmarshalNID2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) {
 	var vSlice []interface{}
 	if v != nil {
-		if tmp1, ok := v.([]interface{}); ok {
-			vSlice = tmp1
-		} else {
-			vSlice = []interface{}{v}
-		}
+		vSlice = graphql.CoerceList(v)
 	}
 	var err error
 	res := make([]string, len(vSlice))
@@ -3452,11 +3815,7 @@ func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Conte
 func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) {
 	var vSlice []interface{}
 	if v != nil {
-		if tmp1, ok := v.([]interface{}); ok {
-			vSlice = tmp1
-		} else {
-			vSlice = []interface{}{v}
-		}
+		vSlice = graphql.CoerceList(v)
 	}
 	var err error
 	res := make([]string, len(vSlice))
@@ -3663,7 +4022,8 @@ func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interf
 }
 
 func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler {
-	return graphql.MarshalBoolean(v)
+	res := graphql.MarshalBoolean(v)
+	return res
 }
 
 func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) {
@@ -3678,7 +4038,8 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
 	if v == nil {
 		return graphql.Null
 	}
-	return graphql.MarshalBoolean(*v)
+	res := graphql.MarshalBoolean(*v)
+	return res
 }
 
 func (ec *executionContext) unmarshalODate2ᚖstring(ctx context.Context, v interface{}) (*string, error) {
@@ -3693,7 +4054,8 @@ func (ec *executionContext) marshalODate2ᚖstring(ctx context.Context, sel ast.
 	if v == nil {
 		return graphql.Null
 	}
-	return graphql.MarshalString(*v)
+	res := graphql.MarshalString(*v)
+	return res
 }
 
 func (ec *executionContext) marshalOHair2ᚖgithubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐHair(ctx context.Context, sel ast.SelectionSet, v *Hair) graphql.Marshaler {
@@ -3715,7 +4077,8 @@ func (ec *executionContext) marshalOID2ᚖstring(ctx context.Context, sel ast.Se
 	if v == nil {
 		return graphql.Null
 	}
-	return graphql.MarshalID(*v)
+	res := graphql.MarshalID(*v)
+	return res
 }
 
 func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) {
@@ -3730,7 +4093,8 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele
 	if v == nil {
 		return graphql.Null
 	}
-	return graphql.MarshalInt(*v)
+	res := graphql.MarshalInt(*v)
+	return res
 }
 
 func (ec *executionContext) marshalOLucky2githubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐLucky(ctx context.Context, sel ast.SelectionSet, v Lucky) graphql.Marshaler {
@@ -3740,15 +4104,6 @@ func (ec *executionContext) marshalOLucky2githubᚗcomᚋKhanᚋgenqlientᚋinte
 	return ec._Lucky(ctx, sel, v)
 }
 
-func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) {
-	res, err := graphql.UnmarshalString(v)
-	return res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
-	return graphql.MarshalString(v)
-}
-
 func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) {
 	if v == nil {
 		return nil, nil
@@ -3761,7 +4116,8 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as
 	if v == nil {
 		return graphql.Null
 	}
-	return graphql.MarshalString(*v)
+	res := graphql.MarshalString(*v)
+	return res
 }
 
 func (ec *executionContext) marshalOUser2ᚕᚖgithubᚗcomᚋKhanᚋgenqlientᚋinternalᚋintegrationᚋserverᚐUser(ctx context.Context, sel ast.SelectionSet, v []*User) graphql.Marshaler {
diff --git a/internal/integration/server/server.go b/internal/integration/server/server.go
index 6988356..e94adb4 100644
--- a/internal/integration/server/server.go
+++ b/internal/integration/server/server.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"net/http/httptest"
 
+	"github.com/99designs/gqlgen/graphql"
 	"github.com/99designs/gqlgen/graphql/handler"
 	"github.com/99designs/gqlgen/graphql/handler/transport"
 )
@@ -131,6 +132,10 @@ func (r *queryResolver) Fail(ctx context.Context) (*bool, error) {
 func RunServer() *httptest.Server {
 	gqlgenServer := handler.New(NewExecutableSchema(Config{Resolvers: &resolver{}}))
 	gqlgenServer.AddTransport(transport.POST{})
+	gqlgenServer.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
+		graphql.RegisterExtension(ctx, "foobar", "test")
+		return next(ctx)
+	})
 	return httptest.NewServer(gqlgenServer)
 }
 


Test patch:
diff --git a/generate/generate_test.go b/generate/generate_test.go
index 49ba55b..762cb47 100644
--- a/generate/generate_test.go
+++ b/generate/generate_test.go
@@ -191,6 +191,10 @@ func TestGenerateWithConfig(t *testing.T) {
 			ClientGetter: "github.com/Khan/genqlient/internal/testutil.GetClientFromNowhere",
 			ContextType:  "-",
 		}},
+		{"Extensions", "", &Config{
+			Generated:  "generated.go",
+			Extensions: true,
+		}},
 	}
 
 	sourceFilename := "SimpleQuery.graphql"
diff --git a/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go
index 1e562dc..d514e91 100644
--- a/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-ComplexInlineFragments.graphql-ComplexInlineFragments.graphql.go
@@ -1348,13 +1348,9 @@ func (v *ComplexInlineFragmentsRootTopic) GetName() string { return v.Name }
 func ComplexInlineFragments(
 	client graphql.Client,
 ) (*ComplexInlineFragmentsResponse, error) {
-	var err error
-
-	var retval ComplexInlineFragmentsResponse
-	err = client.MakeRequest(
-		nil,
-		"ComplexInlineFragments",
-		`
+	req := &graphql.Request{
+		OpName: "ComplexInlineFragments",
+		Query: `
 query ComplexInlineFragments {
 	root {
 		id
@@ -1441,9 +1437,18 @@ query ComplexInlineFragments {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data ComplexInlineFragmentsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go
index 566d18b..15603b2 100644
--- a/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-ComplexNamedFragments.graphql-ComplexNamedFragments.graphql.go
@@ -1742,13 +1742,9 @@ func (v *VideoFieldsThumbnail) GetId() testutil.ID { return v.Id }
 func ComplexNamedFragments(
 	client graphql.Client,
 ) (*ComplexNamedFragmentsResponse, error) {
-	var err error
-
-	var retval ComplexNamedFragmentsResponse
-	err = client.MakeRequest(
-		nil,
-		"ComplexNamedFragments",
-		`
+	req := &graphql.Request{
+		OpName: "ComplexNamedFragments",
+		Query: `
 query ComplexNamedFragments {
 	... on Query {
 		... QueryFragment
@@ -1807,9 +1803,18 @@ fragment MoreVideoFields on Video {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data ComplexNamedFragmentsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-CustomMarshal.graphql-CustomMarshal.graphql.go b/generate/testdata/snapshots/TestGenerate-CustomMarshal.graphql-CustomMarshal.graphql.go
index e8c450d..004d9db 100644
--- a/generate/testdata/snapshots/TestGenerate-CustomMarshal.graphql-CustomMarshal.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-CustomMarshal.graphql-CustomMarshal.graphql.go
@@ -178,16 +178,9 @@ func CustomMarshal(
 	client graphql.Client,
 	date time.Time,
 ) (*CustomMarshalResponse, error) {
-	__input := __CustomMarshalInput{
-		Date: date,
-	}
-	var err error
-
-	var retval CustomMarshalResponse
-	err = client.MakeRequest(
-		nil,
-		"CustomMarshal",
-		`
+	req := &graphql.Request{
+		OpName: "CustomMarshal",
+		Query: `
 query CustomMarshal ($date: Date!) {
 	usersBornOn(date: $date) {
 		id
@@ -195,9 +188,21 @@ query CustomMarshal ($date: Date!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__CustomMarshalInput{
+			Date: date,
+		},
+	}
+	var err error
+
+	var data CustomMarshalResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-CustomMarshalSlice.graphql-CustomMarshalSlice.graphql.go b/generate/testdata/snapshots/TestGenerate-CustomMarshalSlice.graphql-CustomMarshalSlice.graphql.go
index 0156935..26e2b70 100644
--- a/generate/testdata/snapshots/TestGenerate-CustomMarshalSlice.graphql-CustomMarshalSlice.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-CustomMarshalSlice.graphql-CustomMarshalSlice.graphql.go
@@ -208,25 +208,30 @@ func CustomMarshalSlice(
 	datesss [][][]time.Time,
 	datesssp [][][]*time.Time,
 ) (*CustomMarshalSliceResponse, error) {
-	__input := __CustomMarshalSliceInput{
-		Datesss:  datesss,
-		Datesssp: datesssp,
-	}
-	var err error
-
-	var retval CustomMarshalSliceResponse
-	err = client.MakeRequest(
-		nil,
-		"CustomMarshalSlice",
-		`
+	req := &graphql.Request{
+		OpName: "CustomMarshalSlice",
+		Query: `
 query CustomMarshalSlice ($datesss: [[[Date!]!]!]!, $datesssp: [[[Date!]!]!]!) {
 	acceptsListOfListOfListsOfDates(datesss: $datesss)
 	withPointer: acceptsListOfListOfListsOfDates(datesss: $datesssp)
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__CustomMarshalSliceInput{
+			Datesss:  datesss,
+			Datesssp: datesssp,
+		},
+	}
+	var err error
+
+	var data CustomMarshalSliceResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-DateTime.graphql-DateTime.graphql.go b/generate/testdata/snapshots/TestGenerate-DateTime.graphql-DateTime.graphql.go
index 581ec42..94e069d 100644
--- a/generate/testdata/snapshots/TestGenerate-DateTime.graphql-DateTime.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-DateTime.graphql-DateTime.graphql.go
@@ -33,24 +33,29 @@ func convertTimezone(
 	dt time.Time,
 	tz string,
 ) (*convertTimezoneResponse, error) {
-	__input := __convertTimezoneInput{
-		Dt: dt,
-		Tz: tz,
+	req := &graphql.Request{
+		OpName: "convertTimezone",
+		Query: `
+query convertTimezone ($dt: DateTime!, $tz: String) {
+	convert(dt: $dt, tz: $tz)
+}
+`,
+		Variables: &__convertTimezoneInput{
+			Dt: dt,
+			Tz: tz,
+		},
 	}
 	var err error
 
-	var retval convertTimezoneResponse
+	var data convertTimezoneResponse
+	resp := &graphql.Response{Data: &data}
+
 	err = client.MakeRequest(
 		nil,
-		"convertTimezone",
-		`
-query convertTimezone ($dt: DateTime!, $tz: String) {
-	convert(dt: $dt, tz: $tz)
-}
-`,
-		&retval,
-		&__input,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-EmptyInterface.graphql-EmptyInterface.graphql.go b/generate/testdata/snapshots/TestGenerate-EmptyInterface.graphql-EmptyInterface.graphql.go
index 96726d9..0b30293 100644
--- a/generate/testdata/snapshots/TestGenerate-EmptyInterface.graphql-EmptyInterface.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-EmptyInterface.graphql-EmptyInterface.graphql.go
@@ -23,21 +23,26 @@ func (v *EmptyInterfaceResponse) GetGetComplexJunk() []map[string]*[]*map[string
 func EmptyInterface(
 	client graphql.Client,
 ) (*EmptyInterfaceResponse, error) {
-	var err error
-
-	var retval EmptyInterfaceResponse
-	err = client.MakeRequest(
-		nil,
-		"EmptyInterface",
-		`
+	req := &graphql.Request{
+		OpName: "EmptyInterface",
+		Query: `
 query EmptyInterface {
 	getJunk
 	getComplexJunk
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data EmptyInterfaceResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-Flatten.graphql-Flatten.graphql.go b/generate/testdata/snapshots/TestGenerate-Flatten.graphql-Flatten.graphql.go
index cdb16cc..b22e270 100644
--- a/generate/testdata/snapshots/TestGenerate-Flatten.graphql-Flatten.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-Flatten.graphql-Flatten.graphql.go
@@ -269,13 +269,9 @@ func (v *VideoFieldsParentTopic) GetVideoChildren() []ChildVideoFields { return
 func ComplexNamedFragments(
 	client graphql.Client,
 ) (*InnerQueryFragment, error) {
-	var err error
-
-	var retval InnerQueryFragment
-	err = client.MakeRequest(
-		nil,
-		"ComplexNamedFragments",
-		`
+	req := &graphql.Request{
+		OpName: "ComplexNamedFragments",
+		Query: `
 query ComplexNamedFragments {
 	... QueryFragment
 }
@@ -311,9 +307,18 @@ fragment ChildVideoFields on Video {
 	name
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data InnerQueryFragment
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-InputEnum.graphql-InputEnum.graphql.go b/generate/testdata/snapshots/TestGenerate-InputEnum.graphql-InputEnum.graphql.go
index fc8bde6..b1f28d8 100644
--- a/generate/testdata/snapshots/TestGenerate-InputEnum.graphql-InputEnum.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-InputEnum.graphql-InputEnum.graphql.go
@@ -58,25 +58,30 @@ func InputEnumQuery(
 	client graphql.Client,
 	role Role,
 ) (*InputEnumQueryResponse, error) {
-	__input := __InputEnumQueryInput{
-		Role: role,
-	}
-	var err error
-
-	var retval InputEnumQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"InputEnumQuery",
-		`
+	req := &graphql.Request{
+		OpName: "InputEnumQuery",
+		Query: `
 query InputEnumQuery ($role: Role!) {
 	usersWithRole(role: $role) {
 		id
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__InputEnumQueryInput{
+			Role: role,
+		},
+	}
+	var err error
+
+	var data InputEnumQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-InputObject.graphql-InputObject.graphql.go b/generate/testdata/snapshots/TestGenerate-InputObject.graphql-InputObject.graphql.go
index 4d2cc3c..09be3f3 100644
--- a/generate/testdata/snapshots/TestGenerate-InputObject.graphql-InputObject.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-InputObject.graphql-InputObject.graphql.go
@@ -181,25 +181,30 @@ func InputObjectQuery(
 	client graphql.Client,
 	query UserQueryInput,
 ) (*InputObjectQueryResponse, error) {
-	__input := __InputObjectQueryInput{
-		Query: query,
-	}
-	var err error
-
-	var retval InputObjectQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"InputObjectQuery",
-		`
+	req := &graphql.Request{
+		OpName: "InputObjectQuery",
+		Query: `
 query InputObjectQuery ($query: UserQueryInput) {
 	user(query: $query) {
 		id
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__InputObjectQueryInput{
+			Query: query,
+		},
+	}
+	var err error
+
+	var data InputObjectQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go
index 048b608..596f132 100644
--- a/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-InterfaceListField.graphql-InterfaceListField.graphql.go
@@ -523,13 +523,9 @@ func (v *InterfaceListFieldWithPointerTopicChildrenVideo) GetName() string { ret
 func InterfaceListField(
 	client graphql.Client,
 ) (*InterfaceListFieldResponse, error) {
-	var err error
-
-	var retval InterfaceListFieldResponse
-	err = client.MakeRequest(
-		nil,
-		"InterfaceListField",
-		`
+	req := &graphql.Request{
+		OpName: "InterfaceListField",
+		Query: `
 query InterfaceListField {
 	root {
 		id
@@ -551,9 +547,18 @@ query InterfaceListField {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data InterfaceListFieldResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go
index 8e29f76..b46922f 100644
--- a/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-InterfaceListOfListsOfListsField.graphql-InterfaceListOfListsOfListsField.graphql.go
@@ -509,13 +509,9 @@ func (v *InterfaceListOfListOfListsFieldWithPointerVideo) GetName() *string { re
 func InterfaceListOfListOfListsField(
 	client graphql.Client,
 ) (*InterfaceListOfListOfListsFieldResponse, error) {
-	var err error
-
-	var retval InterfaceListOfListOfListsFieldResponse
-	err = client.MakeRequest(
-		nil,
-		"InterfaceListOfListOfListsField",
-		`
+	req := &graphql.Request{
+		OpName: "InterfaceListOfListOfListsField",
+		Query: `
 query InterfaceListOfListOfListsField {
 	listOfListsOfListsOfContent {
 		__typename
@@ -529,9 +525,18 @@ query InterfaceListOfListOfListsField {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data InterfaceListOfListOfListsFieldResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go
index f69273f..565302e 100644
--- a/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-InterfaceNesting.graphql-InterfaceNesting.graphql.go
@@ -507,13 +507,9 @@ func (v *InterfaceNestingRootTopicChildrenVideo) GetParent() InterfaceNestingRoo
 func InterfaceNesting(
 	client graphql.Client,
 ) (*InterfaceNestingResponse, error) {
-	var err error
-
-	var retval InterfaceNestingResponse
-	err = client.MakeRequest(
-		nil,
-		"InterfaceNesting",
-		`
+	req := &graphql.Request{
+		OpName: "InterfaceNesting",
+		Query: `
 query InterfaceNesting {
 	root {
 		id
@@ -531,9 +527,18 @@ query InterfaceNesting {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data InterfaceNestingResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go
index 6e60049..4fce0d2 100644
--- a/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-InterfaceNoFragments.graphql-InterfaceNoFragments.graphql.go
@@ -629,13 +629,9 @@ func (v *InterfaceNoFragmentsQueryWithPointerVideo) GetName() *string { return v
 func InterfaceNoFragmentsQuery(
 	client graphql.Client,
 ) (*InterfaceNoFragmentsQueryResponse, error) {
-	var err error
-
-	var retval InterfaceNoFragmentsQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"InterfaceNoFragmentsQuery",
-		`
+	req := &graphql.Request{
+		OpName: "InterfaceNoFragmentsQuery",
+		Query: `
 query InterfaceNoFragmentsQuery {
 	root {
 		id
@@ -658,9 +654,18 @@ query InterfaceNoFragmentsQuery {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data InterfaceNoFragmentsQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-ListInput.graphql-ListInput.graphql.go b/generate/testdata/snapshots/TestGenerate-ListInput.graphql-ListInput.graphql.go
index 4bf5172..818104a 100644
--- a/generate/testdata/snapshots/TestGenerate-ListInput.graphql-ListInput.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-ListInput.graphql-ListInput.graphql.go
@@ -45,25 +45,30 @@ func ListInputQuery(
 	client graphql.Client,
 	names []string,
 ) (*ListInputQueryResponse, error) {
-	__input := __ListInputQueryInput{
-		Names: names,
-	}
-	var err error
-
-	var retval ListInputQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"ListInputQuery",
-		`
+	req := &graphql.Request{
+		OpName: "ListInputQuery",
+		Query: `
 query ListInputQuery ($names: [String]) {
 	user(query: {names:$names}) {
 		id
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__ListInputQueryInput{
+			Names: names,
+		},
+	}
+	var err error
+
+	var data ListInputQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-ListOfListsOfLists.graphql-ListOfListsOfLists.graphql.go b/generate/testdata/snapshots/TestGenerate-ListOfListsOfLists.graphql-ListOfListsOfLists.graphql.go
index f6399ad..b77ff40 100644
--- a/generate/testdata/snapshots/TestGenerate-ListOfListsOfLists.graphql-ListOfListsOfLists.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-ListOfListsOfLists.graphql-ListOfListsOfLists.graphql.go
@@ -19,20 +19,25 @@ func (v *ListOfListsOfListsResponse) GetListOfListsOfLists() [][][]string {
 func ListOfListsOfLists(
 	client graphql.Client,
 ) (*ListOfListsOfListsResponse, error) {
-	var err error
-
-	var retval ListOfListsOfListsResponse
-	err = client.MakeRequest(
-		nil,
-		"ListOfListsOfLists",
-		`
+	req := &graphql.Request{
+		OpName: "ListOfListsOfLists",
+		Query: `
 query ListOfListsOfLists {
 	listOfListsOfLists
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data ListOfListsOfListsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-MultipleDirectives.graphql-MultipleDirectives.graphql.go b/generate/testdata/snapshots/TestGenerate-MultipleDirectives.graphql-MultipleDirectives.graphql.go
index 6e39da0..78cb7b7 100644
--- a/generate/testdata/snapshots/TestGenerate-MultipleDirectives.graphql-MultipleDirectives.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-MultipleDirectives.graphql-MultipleDirectives.graphql.go
@@ -330,17 +330,9 @@ func MultipleDirectives(
 	query MyInput,
 	queries []*UserQueryInput,
 ) (*MyMultipleDirectivesResponse, error) {
-	__input := __MultipleDirectivesInput{
-		Query:   query,
-		Queries: queries,
-	}
-	var err error
-
-	var retval MyMultipleDirectivesResponse
-	err = client.MakeRequest(
-		nil,
-		"MultipleDirectives",
-		`
+	req := &graphql.Request{
+		OpName: "MultipleDirectives",
+		Query: `
 query MultipleDirectives ($query: UserQueryInput, $queries: [UserQueryInput]) {
 	user(query: $query) {
 		id
@@ -350,9 +342,22 @@ query MultipleDirectives ($query: UserQueryInput, $queries: [UserQueryInput]) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__MultipleDirectivesInput{
+			Query:   query,
+			Queries: queries,
+		},
+	}
+	var err error
+
+	var data MyMultipleDirectivesResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-Omitempty.graphql-Omitempty.graphql.go b/generate/testdata/snapshots/TestGenerate-Omitempty.graphql-Omitempty.graphql.go
index 2413984..ba0a9ef 100644
--- a/generate/testdata/snapshots/TestGenerate-Omitempty.graphql-Omitempty.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-Omitempty.graphql-Omitempty.graphql.go
@@ -227,20 +227,9 @@ func OmitEmptyQuery(
 	tz string,
 	tzNoOmitEmpty string,
 ) (*OmitEmptyQueryResponse, error) {
-	__input := __OmitEmptyQueryInput{
-		Query:         query,
-		Queries:       queries,
-		Dt:            dt,
-		Tz:            tz,
-		TzNoOmitEmpty: tzNoOmitEmpty,
-	}
-	var err error
-
-	var retval OmitEmptyQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"OmitEmptyQuery",
-		`
+	req := &graphql.Request{
+		OpName: "OmitEmptyQuery",
+		Query: `
 query OmitEmptyQuery ($query: UserQueryInput, $queries: [UserQueryInput], $dt: DateTime, $tz: String, $tzNoOmitEmpty: String) {
 	user(query: $query) {
 		id
@@ -252,9 +241,25 @@ query OmitEmptyQuery ($query: UserQueryInput, $queries: [UserQueryInput], $dt: D
 	convert2: maybeConvert(dt: $dt, tz: $tzNoOmitEmpty)
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__OmitEmptyQueryInput{
+			Query:         query,
+			Queries:       queries,
+			Dt:            dt,
+			Tz:            tz,
+			TzNoOmitEmpty: tzNoOmitEmpty,
+		},
+	}
+	var err error
+
+	var data OmitEmptyQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-Pointers.graphql-Pointers.graphql.go b/generate/testdata/snapshots/TestGenerate-Pointers.graphql-Pointers.graphql.go
index 3378941..12e0e9e 100644
--- a/generate/testdata/snapshots/TestGenerate-Pointers.graphql-Pointers.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-Pointers.graphql-Pointers.graphql.go
@@ -236,18 +236,9 @@ func PointersQuery(
 	dt time.Time,
 	tz *string,
 ) (*PointersQueryResponse, error) {
-	__input := __PointersQueryInput{
-		Query: query,
-		Dt:    dt,
-		Tz:    tz,
-	}
-	var err error
-
-	var retval PointersQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"PointersQuery",
-		`
+	req := &graphql.Request{
+		OpName: "PointersQuery",
+		Query: `
 query PointersQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) {
 	user(query: $query) {
 		id
@@ -262,9 +253,23 @@ query PointersQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) {
 	maybeConvert(dt: $dt, tz: $tz)
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__PointersQueryInput{
+			Query: query,
+			Dt:    dt,
+			Tz:    tz,
+		},
+	}
+	var err error
+
+	var data PointersQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-PointersInline.graphql-PointersInline.graphql.go b/generate/testdata/snapshots/TestGenerate-PointersInline.graphql-PointersInline.graphql.go
index a01827a..996202c 100644
--- a/generate/testdata/snapshots/TestGenerate-PointersInline.graphql-PointersInline.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-PointersInline.graphql-PointersInline.graphql.go
@@ -233,18 +233,9 @@ func PointersQuery(
 	dt *time.Time,
 	tz string,
 ) (*PointersQueryResponse, error) {
-	__input := __PointersQueryInput{
-		Query: query,
-		Dt:    dt,
-		Tz:    tz,
-	}
-	var err error
-
-	var retval PointersQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"PointersQuery",
-		`
+	req := &graphql.Request{
+		OpName: "PointersQuery",
+		Query: `
 query PointersQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) {
 	user(query: $query) {
 		id
@@ -259,9 +250,23 @@ query PointersQuery ($query: UserQueryInput, $dt: DateTime, $tz: String) {
 	maybeConvert(dt: $dt, tz: $tz)
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__PointersQueryInput{
+			Query: query,
+			Dt:    dt,
+			Tz:    tz,
+		},
+	}
+	var err error
+
+	var data PointersQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-Pokemon.graphql-Pokemon.graphql.go b/generate/testdata/snapshots/TestGenerate-Pokemon.graphql-Pokemon.graphql.go
index edc9fcf..749e879 100644
--- a/generate/testdata/snapshots/TestGenerate-Pokemon.graphql-Pokemon.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-Pokemon.graphql-Pokemon.graphql.go
@@ -75,16 +75,9 @@ func GetPokemonSiblings(
 	client graphql.Client,
 	input testutil.Pokemon,
 ) (*GetPokemonSiblingsResponse, error) {
-	__input := __GetPokemonSiblingsInput{
-		Input: input,
-	}
-	var err error
-
-	var retval GetPokemonSiblingsResponse
-	err = client.MakeRequest(
-		nil,
-		"GetPokemonSiblings",
-		`
+	req := &graphql.Request{
+		OpName: "GetPokemonSiblings",
+		Query: `
 query GetPokemonSiblings ($input: PokemonInput!) {
 	user(query: {hasPokemon:$input}) {
 		id
@@ -101,9 +94,21 @@ query GetPokemonSiblings ($input: PokemonInput!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__GetPokemonSiblingsInput{
+			Input: input,
+		},
+	}
+	var err error
+
+	var data GetPokemonSiblingsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-QueryWithAlias.graphql-QueryWithAlias.graphql.go b/generate/testdata/snapshots/TestGenerate-QueryWithAlias.graphql-QueryWithAlias.graphql.go
index 6af1bfc..784bbb3 100644
--- a/generate/testdata/snapshots/TestGenerate-QueryWithAlias.graphql-QueryWithAlias.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-QueryWithAlias.graphql-QueryWithAlias.graphql.go
@@ -43,13 +43,9 @@ func (v *QueryWithAliasUser) GetOtherID() testutil.ID { return v.OtherID }
 func QueryWithAlias(
 	client graphql.Client,
 ) (*QueryWithAliasResponse, error) {
-	var err error
-
-	var retval QueryWithAliasResponse
-	err = client.MakeRequest(
-		nil,
-		"QueryWithAlias",
-		`
+	req := &graphql.Request{
+		OpName: "QueryWithAlias",
+		Query: `
 query QueryWithAlias {
 	User: user {
 		ID: id
@@ -57,9 +53,18 @@ query QueryWithAlias {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data QueryWithAliasResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-QueryWithDoubleAlias.graphql-QueryWithDoubleAlias.graphql.go b/generate/testdata/snapshots/TestGenerate-QueryWithDoubleAlias.graphql-QueryWithDoubleAlias.graphql.go
index 0544f5a..6e2213a 100644
--- a/generate/testdata/snapshots/TestGenerate-QueryWithDoubleAlias.graphql-QueryWithDoubleAlias.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-QueryWithDoubleAlias.graphql-QueryWithDoubleAlias.graphql.go
@@ -43,13 +43,9 @@ func (v *QueryWithDoubleAliasUser) GetAlsoID() testutil.ID { return v.AlsoID }
 func QueryWithDoubleAlias(
 	client graphql.Client,
 ) (*QueryWithDoubleAliasResponse, error) {
-	var err error
-
-	var retval QueryWithDoubleAliasResponse
-	err = client.MakeRequest(
-		nil,
-		"QueryWithDoubleAlias",
-		`
+	req := &graphql.Request{
+		OpName: "QueryWithDoubleAlias",
+		Query: `
 query QueryWithDoubleAlias {
 	user {
 		ID: id
@@ -57,9 +53,18 @@ query QueryWithDoubleAlias {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data QueryWithDoubleAliasResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-QueryWithEnums.graphql-QueryWithEnums.graphql.go b/generate/testdata/snapshots/TestGenerate-QueryWithEnums.graphql-QueryWithEnums.graphql.go
index f14f00f..52f5199 100644
--- a/generate/testdata/snapshots/TestGenerate-QueryWithEnums.graphql-QueryWithEnums.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-QueryWithEnums.graphql-QueryWithEnums.graphql.go
@@ -65,13 +65,9 @@ const (
 func QueryWithEnums(
 	client graphql.Client,
 ) (*QueryWithEnumsResponse, error) {
-	var err error
-
-	var retval QueryWithEnumsResponse
-	err = client.MakeRequest(
-		nil,
-		"QueryWithEnums",
-		`
+	req := &graphql.Request{
+		OpName: "QueryWithEnums",
+		Query: `
 query QueryWithEnums {
 	user {
 		roles
@@ -81,9 +77,18 @@ query QueryWithEnums {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data QueryWithEnumsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-QueryWithSlices.graphql-QueryWithSlices.graphql.go b/generate/testdata/snapshots/TestGenerate-QueryWithSlices.graphql-QueryWithSlices.graphql.go
index f83f4f6..e7347fa 100644
--- a/generate/testdata/snapshots/TestGenerate-QueryWithSlices.graphql-QueryWithSlices.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-QueryWithSlices.graphql-QueryWithSlices.graphql.go
@@ -44,13 +44,9 @@ func (v *QueryWithSlicesUser) GetEmailsWithNullsOrNull() []string { return v.Ema
 func QueryWithSlices(
 	client graphql.Client,
 ) (*QueryWithSlicesResponse, error) {
-	var err error
-
-	var retval QueryWithSlicesResponse
-	err = client.MakeRequest(
-		nil,
-		"QueryWithSlices",
-		`
+	req := &graphql.Request{
+		OpName: "QueryWithSlices",
+		Query: `
 query QueryWithSlices {
 	user {
 		emails
@@ -60,9 +56,18 @@ query QueryWithSlices {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data QueryWithSlicesResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-QueryWithStructs.graphql-QueryWithStructs.graphql.go b/generate/testdata/snapshots/TestGenerate-QueryWithStructs.graphql-QueryWithStructs.graphql.go
index 0c6e9be..63ac7fb 100644
--- a/generate/testdata/snapshots/TestGenerate-QueryWithStructs.graphql-QueryWithStructs.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-QueryWithStructs.graphql-QueryWithStructs.graphql.go
@@ -46,13 +46,9 @@ func (v *QueryWithStructsUserAuthMethodsAuthMethod) GetEmail() string { return v
 func QueryWithStructs(
 	client graphql.Client,
 ) (*QueryWithStructsResponse, error) {
-	var err error
-
-	var retval QueryWithStructsResponse
-	err = client.MakeRequest(
-		nil,
-		"QueryWithStructs",
-		`
+	req := &graphql.Request{
+		OpName: "QueryWithStructs",
+		Query: `
 query QueryWithStructs {
 	user {
 		authMethods {
@@ -62,9 +58,18 @@ query QueryWithStructs {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data QueryWithStructsResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-Recursion.graphql-Recursion.graphql.go b/generate/testdata/snapshots/TestGenerate-Recursion.graphql-Recursion.graphql.go
index 6547708..b8cab24 100644
--- a/generate/testdata/snapshots/TestGenerate-Recursion.graphql-Recursion.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-Recursion.graphql-Recursion.graphql.go
@@ -72,16 +72,9 @@ func Recursion(
 	client graphql.Client,
 	input RecursiveInput,
 ) (*RecursionResponse, error) {
-	__input := __RecursionInput{
-		Input: input,
-	}
-	var err error
-
-	var retval RecursionResponse
-	err = client.MakeRequest(
-		nil,
-		"Recursion",
-		`
+	req := &graphql.Request{
+		OpName: "Recursion",
+		Query: `
 query Recursion ($input: RecursiveInput!) {
 	recur(input: $input) {
 		rec {
@@ -94,9 +87,21 @@ query Recursion ($input: RecursiveInput!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__RecursionInput{
+			Input: input,
+		},
+	}
+	var err error
+
+	var data RecursionResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-SimpleInlineFragment.graphql-SimpleInlineFragment.graphql.go b/generate/testdata/snapshots/TestGenerate-SimpleInlineFragment.graphql-SimpleInlineFragment.graphql.go
index b3cf78a..b63971f 100644
--- a/generate/testdata/snapshots/TestGenerate-SimpleInlineFragment.graphql-SimpleInlineFragment.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-SimpleInlineFragment.graphql-SimpleInlineFragment.graphql.go
@@ -242,13 +242,9 @@ func (v *SimpleInlineFragmentResponse) __premarshalJSON() (*__premarshalSimpleIn
 func SimpleInlineFragment(
 	client graphql.Client,
 ) (*SimpleInlineFragmentResponse, error) {
-	var err error
-
-	var retval SimpleInlineFragmentResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleInlineFragment",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleInlineFragment",
+		Query: `
 query SimpleInlineFragment {
 	randomItem {
 		__typename
@@ -263,9 +259,18 @@ query SimpleInlineFragment {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data SimpleInlineFragmentResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-SimpleInput.graphql-SimpleInput.graphql.go b/generate/testdata/snapshots/TestGenerate-SimpleInput.graphql-SimpleInput.graphql.go
index 78d6209..7fe46d4 100644
--- a/generate/testdata/snapshots/TestGenerate-SimpleInput.graphql-SimpleInput.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-SimpleInput.graphql-SimpleInput.graphql.go
@@ -45,25 +45,30 @@ func SimpleInputQuery(
 	client graphql.Client,
 	name string,
 ) (*SimpleInputQueryResponse, error) {
-	__input := __SimpleInputQueryInput{
-		Name: name,
-	}
-	var err error
-
-	var retval SimpleInputQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleInputQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleInputQuery",
+		Query: `
 query SimpleInputQuery ($name: String!) {
 	user(query: {name:$name}) {
 		id
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__SimpleInputQueryInput{
+			Name: name,
+		},
+	}
+	var err error
+
+	var data SimpleInputQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-SimpleMutation.graphql-SimpleMutation.graphql.go b/generate/testdata/snapshots/TestGenerate-SimpleMutation.graphql-SimpleMutation.graphql.go
index 8601bc4..15a13fb 100644
--- a/generate/testdata/snapshots/TestGenerate-SimpleMutation.graphql-SimpleMutation.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-SimpleMutation.graphql-SimpleMutation.graphql.go
@@ -49,16 +49,9 @@ func SimpleMutation(
 	client graphql.Client,
 	name string,
 ) (*SimpleMutationResponse, error) {
-	__input := __SimpleMutationInput{
-		Name: name,
-	}
-	var err error
-
-	var retval SimpleMutationResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleMutation",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleMutation",
+		Query: `
 mutation SimpleMutation ($name: String!) {
 	createUser(name: $name) {
 		id
@@ -66,9 +59,21 @@ mutation SimpleMutation ($name: String!) {
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__SimpleMutationInput{
+			Name: name,
+		},
+	}
+	var err error
+
+	var data SimpleMutationResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-SimpleNamedFragment.graphql-SimpleNamedFragment.graphql.go b/generate/testdata/snapshots/TestGenerate-SimpleNamedFragment.graphql-SimpleNamedFragment.graphql.go
index 1773fba..dbfc062 100644
--- a/generate/testdata/snapshots/TestGenerate-SimpleNamedFragment.graphql-SimpleNamedFragment.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-SimpleNamedFragment.graphql-SimpleNamedFragment.graphql.go
@@ -549,13 +549,9 @@ func (v *VideoFieldsThumbnail) GetId() testutil.ID { return v.Id }
 func SimpleNamedFragment(
 	client graphql.Client,
 ) (*SimpleNamedFragmentResponse, error) {
-	var err error
-
-	var retval SimpleNamedFragmentResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleNamedFragment",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleNamedFragment",
+		Query: `
 query SimpleNamedFragment {
 	randomItem {
 		__typename
@@ -578,9 +574,18 @@ fragment VideoFields on Video {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data SimpleNamedFragmentResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-SimpleQuery.graphql-SimpleQuery.graphql.go b/generate/testdata/snapshots/TestGenerate-SimpleQuery.graphql-SimpleQuery.graphql.go
index 2d9ead5..645e111 100644
--- a/generate/testdata/snapshots/TestGenerate-SimpleQuery.graphql-SimpleQuery.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-SimpleQuery.graphql-SimpleQuery.graphql.go
@@ -36,22 +36,27 @@ func (v *SimpleQueryUser) GetId() testutil.ID { return v.Id }
 func SimpleQuery(
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-StructOption.graphql-StructOption.graphql.go b/generate/testdata/snapshots/TestGenerate-StructOption.graphql-StructOption.graphql.go
index 75fe942..fdec034 100644
--- a/generate/testdata/snapshots/TestGenerate-StructOption.graphql-StructOption.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-StructOption.graphql-StructOption.graphql.go
@@ -427,13 +427,9 @@ func (v *VideoFields) GetDuration() int { return v.Duration }
 func StructOption(
 	client graphql.Client,
 ) (*StructOptionResponse, error) {
-	var err error
-
-	var retval StructOptionResponse
-	err = client.MakeRequest(
-		nil,
-		"StructOption",
-		`
+	req := &graphql.Request{
+		OpName: "StructOption",
+		Query: `
 query StructOption {
 	root {
 		id
@@ -462,9 +458,18 @@ fragment VideoFields on Video {
 	duration
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data StructOptionResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-TypeName.graphql-TypeName.graphql.go b/generate/testdata/snapshots/TestGenerate-TypeName.graphql-TypeName.graphql.go
index da9892c..899cc2d 100644
--- a/generate/testdata/snapshots/TestGenerate-TypeName.graphql-TypeName.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-TypeName.graphql-TypeName.graphql.go
@@ -40,13 +40,9 @@ func (v *TypeNameQueryUser) GetId() testutil.ID { return v.Id }
 func TypeNameQuery(
 	client graphql.Client,
 ) (*TypeNameQueryResponse, error) {
-	var err error
-
-	var retval TypeNameQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"TypeNameQuery",
-		`
+	req := &graphql.Request{
+		OpName: "TypeNameQuery",
+		Query: `
 query TypeNameQuery {
 	user {
 		__typename
@@ -54,9 +50,18 @@ query TypeNameQuery {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data TypeNameQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-TypeNames.graphql-TypeNames.graphql.go b/generate/testdata/snapshots/TestGenerate-TypeNames.graphql-TypeNames.graphql.go
index f79932f..9ee556a 100644
--- a/generate/testdata/snapshots/TestGenerate-TypeNames.graphql-TypeNames.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-TypeNames.graphql-TypeNames.graphql.go
@@ -267,13 +267,9 @@ func (v *User) GetName() string { return v.Name }
 func TypeNames(
 	client graphql.Client,
 ) (*Resp, error) {
-	var err error
-
-	var retval Resp
-	err = client.MakeRequest(
-		nil,
-		"TypeNames",
-		`
+	req := &graphql.Request{
+		OpName: "TypeNames",
+		Query: `
 query TypeNames {
 	user {
 		id
@@ -290,9 +286,18 @@ query TypeNames {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data Resp
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go b/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go
index d6d75ab..195a601 100644
--- a/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-UnionNoFragments.graphql-UnionNoFragments.graphql.go
@@ -177,22 +177,27 @@ func (v *UnionNoFragmentsQueryResponse) __premarshalJSON() (*__premarshalUnionNo
 func UnionNoFragmentsQuery(
 	client graphql.Client,
 ) (*UnionNoFragmentsQueryResponse, error) {
-	var err error
-
-	var retval UnionNoFragmentsQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"UnionNoFragmentsQuery",
-		`
+	req := &graphql.Request{
+		OpName: "UnionNoFragmentsQuery",
+		Query: `
 query UnionNoFragmentsQuery {
 	randomLeaf {
 		__typename
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data UnionNoFragmentsQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-UsesEnumTwice.graphql-UsesEnumTwice.graphql.go b/generate/testdata/snapshots/TestGenerate-UsesEnumTwice.graphql-UsesEnumTwice.graphql.go
index 5864d35..06b39fe 100644
--- a/generate/testdata/snapshots/TestGenerate-UsesEnumTwice.graphql-UsesEnumTwice.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-UsesEnumTwice.graphql-UsesEnumTwice.graphql.go
@@ -65,13 +65,9 @@ func (v *UsesEnumTwiceQueryResponse) GetOtherUser() UsesEnumTwiceQueryOtherUser
 func UsesEnumTwiceQuery(
 	client graphql.Client,
 ) (*UsesEnumTwiceQueryResponse, error) {
-	var err error
-
-	var retval UsesEnumTwiceQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"UsesEnumTwiceQuery",
-		`
+	req := &graphql.Request{
+		OpName: "UsesEnumTwiceQuery",
+		Query: `
 query UsesEnumTwiceQuery {
 	Me: user {
 		roles
@@ -81,9 +77,18 @@ query UsesEnumTwiceQuery {
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data UsesEnumTwiceQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go b/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go
index 81eebc2..8aabfa6 100644
--- a/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go
+++ b/generate/testdata/snapshots/TestGenerate-unexported.graphql-unexported.graphql.go
@@ -181,25 +181,30 @@ func unexported(
 	client graphql.Client,
 	query UserQueryInput,
 ) (*unexportedResponse, error) {
-	__input := __unexportedInput{
-		Query: query,
-	}
-	var err error
-
-	var retval unexportedResponse
-	err = client.MakeRequest(
-		nil,
-		"unexported",
-		`
+	req := &graphql.Request{
+		OpName: "unexported",
+		Query: `
 query unexported ($query: UserQueryInput) {
 	user(query: $query) {
 		id
 	}
 }
 `,
-		&retval,
-		&__input,
+		Variables: &__unexportedInput{
+			Query: query,
+		},
+	}
+	var err error
+
+	var data unexportedResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetter-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetter-testdata-queries-generated.go
index 360947f..d5ac56d 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetter-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetter-testdata-queries-generated.go
@@ -5,6 +5,7 @@ package queries
 import (
 	"context"
 
+	"github.com/Khan/genqlient/graphql"
 	"github.com/Khan/genqlient/internal/testutil"
 )
 
@@ -37,26 +38,33 @@ func (v *SimpleQueryUser) GetId() string { return v.Id }
 func SimpleQuery(
 	ctx context.Context,
 ) (*SimpleQueryResponse, error) {
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
+query SimpleQuery {
+	user {
+		id
+	}
+}
+`,
+	}
 	var err error
-	client, err := testutil.GetClientFromContext(ctx)
+	var client graphql.Client
+
+	client, err = testutil.GetClientFromContext(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	var retval SimpleQueryResponse
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
 	err = client.MakeRequest(
 		ctx,
-		"SimpleQuery",
-		`
-query SimpleQuery {
-	user {
-		id
-	}
-}
-`,
-		&retval,
-		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterCustomContext-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterCustomContext-testdata-queries-generated.go
index 36e6798..61b5518 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterCustomContext-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterCustomContext-testdata-queries-generated.go
@@ -5,6 +5,7 @@ package queries
 import (
 	"context"
 
+	"github.com/Khan/genqlient/graphql"
 	"github.com/Khan/genqlient/internal/testutil"
 )
 
@@ -40,26 +41,33 @@ func (v *SimpleQueryUser) GetId() string { return v.Id }
 func SimpleQuery(
 	ctx testutil.MyContext,
 ) (*SimpleQueryResponse, error) {
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
+query SimpleQuery {
+	user {
+		id
+	}
+}
+`,
+	}
 	var err error
-	client, err := testutil.GetClientFromMyContext(ctx)
+	var client graphql.Client
+
+	client, err = testutil.GetClientFromMyContext(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	var retval SimpleQueryResponse
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
 	err = client.MakeRequest(
 		ctx,
-		"SimpleQuery",
-		`
-query SimpleQuery {
-	user {
-		id
-	}
-}
-`,
-		&retval,
-		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterNoContext-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterNoContext-testdata-queries-generated.go
index 9d3e139..e35911a 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterNoContext-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-ClientGetterNoContext-testdata-queries-generated.go
@@ -3,6 +3,7 @@
 package queries
 
 import (
+	"github.com/Khan/genqlient/graphql"
 	"github.com/Khan/genqlient/internal/testutil"
 )
 
@@ -33,26 +34,33 @@ type SimpleQueryUser struct {
 func (v *SimpleQueryUser) GetId() string { return v.Id }
 
 func SimpleQuery() (*SimpleQueryResponse, error) {
-	var err error
-	client, err := testutil.GetClientFromNowhere()
-	if err != nil {
-		return nil, err
-	}
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+	var client graphql.Client
+
+	client, err = testutil.GetClientFromNowhere()
+	if err != nil {
+		return nil, err
+	}
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-CustomContext-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-CustomContext-testdata-queries-generated.go
index d15c27a..790ecb8 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-CustomContext-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-CustomContext-testdata-queries-generated.go
@@ -42,22 +42,27 @@ func SimpleQuery(
 	ctx testutil.MyContext,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-DefaultConfig-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-DefaultConfig-testdata-queries-generated.go
index 6b08b6b..bb9d5d5 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-DefaultConfig-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-DefaultConfig-testdata-queries-generated.go
@@ -38,22 +38,27 @@ func SimpleQuery(
 	ctx context.Context,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-ExportOperations-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-ExportOperations-testdata-queries-generated.go
index 6b08b6b..bb9d5d5 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-ExportOperations-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-ExportOperations-testdata-queries-generated.go
@@ -38,22 +38,27 @@ func SimpleQuery(
 	ctx context.Context,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-Extensions-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-Extensions-testdata-queries-generated.go
new file mode 100644
index 0000000..691c2ba
--- /dev/null
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-Extensions-testdata-queries-generated.go
@@ -0,0 +1,64 @@
+// Code generated by github.com/Khan/genqlient, DO NOT EDIT.
+
+package queries
+
+import (
+	"context"
+
+	"github.com/Khan/genqlient/graphql"
+)
+
+// SimpleQueryResponse is returned by SimpleQuery on success.
+type SimpleQueryResponse struct {
+	// user looks up a user by some stuff.
+	//
+	// See UserQueryInput for what stuff is supported.
+	// If query is null, returns the current user.
+	User SimpleQueryUser `json:"user"`
+}
+
+// GetUser returns SimpleQueryResponse.User, and is useful for accessing the field via an interface.
+func (v *SimpleQueryResponse) GetUser() SimpleQueryUser { return v.User }
+
+// SimpleQueryUser includes the requested fields of the GraphQL type User.
+// The GraphQL type's documentation follows.
+//
+// A User is a user!
+type SimpleQueryUser struct {
+	// id is the user's ID.
+	//
+	// It is stable, unique, and opaque, like all good IDs.
+	Id string `json:"id"`
+}
+
+// GetId returns SimpleQueryUser.Id, and is useful for accessing the field via an interface.
+func (v *SimpleQueryUser) GetId() string { return v.Id }
+
+func SimpleQuery(
+	ctx context.Context,
+	client graphql.Client,
+) (*SimpleQueryResponse, map[string]interface{}, error) {
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
+query SimpleQuery {
+	user {
+		id
+	}
+}
+`,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
+	)
+
+	return &data, resp.Extensions, err
+}
+
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-NoContext-testdata-queries-generated.go b/generate/testdata/snapshots/TestGenerateWithConfig-NoContext-testdata-queries-generated.go
index 16d0538..5318ac7 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-NoContext-testdata-queries-generated.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-NoContext-testdata-queries-generated.go
@@ -35,22 +35,27 @@ func (v *SimpleQueryUser) GetId() string { return v.Id }
 func SimpleQuery(
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		nil,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
 		nil,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-PackageName-testdata-queries-myfile.go b/generate/testdata/snapshots/TestGenerateWithConfig-PackageName-testdata-queries-myfile.go
index 9006b4b..d6dea59 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-PackageName-testdata-queries-myfile.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-PackageName-testdata-queries-myfile.go
@@ -38,22 +38,27 @@ func SimpleQuery(
 	ctx context.Context,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go b/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go
index 24b17f3..31993fd 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-StructReferences-testdata-queries-generated-structrefs.go
@@ -38,22 +38,27 @@ func SimpleQuery(
 	ctx context.Context,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-Subpackage-testdata-queries-mypkg-myfile.go b/generate/testdata/snapshots/TestGenerateWithConfig-Subpackage-testdata-queries-mypkg-myfile.go
index 9006b4b..d6dea59 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-Subpackage-testdata-queries-mypkg-myfile.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-Subpackage-testdata-queries-mypkg-myfile.go
@@ -38,22 +38,27 @@ func SimpleQuery(
 	ctx context.Context,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/generate/testdata/snapshots/TestGenerateWithConfig-SubpackageConfig-testdata-queries-mypkg-myfile.go b/generate/testdata/snapshots/TestGenerateWithConfig-SubpackageConfig-testdata-queries-mypkg-myfile.go
index 9006b4b..d6dea59 100644
--- a/generate/testdata/snapshots/TestGenerateWithConfig-SubpackageConfig-testdata-queries-mypkg-myfile.go
+++ b/generate/testdata/snapshots/TestGenerateWithConfig-SubpackageConfig-testdata-queries-mypkg-myfile.go
@@ -38,22 +38,27 @@ func SimpleQuery(
 	ctx context.Context,
 	client graphql.Client,
 ) (*SimpleQueryResponse, error) {
-	var err error
-
-	var retval SimpleQueryResponse
-	err = client.MakeRequest(
-		ctx,
-		"SimpleQuery",
-		`
+	req := &graphql.Request{
+		OpName: "SimpleQuery",
+		Query: `
 query SimpleQuery {
 	user {
 		id
 	}
 }
 `,
-		&retval,
-		nil,
+	}
+	var err error
+
+	var data SimpleQueryResponse
+	resp := &graphql.Response{Data: &data}
+
+	err = client.MakeRequest(
+		ctx,
+		req,
+		resp,
 	)
-	return &retval, err
+
+	return &data, err
 }
 
diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go
index 55162ad..e41ced5 100644
--- a/internal/integration/integration_test.go
+++ b/internal/integration/integration_test.go
@@ -27,7 +27,7 @@ func TestSimpleQuery(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := simpleQuery(ctx, client)
+	resp, _, err := simpleQuery(ctx, client)
 	require.NoError(t, err)
 
 	assert.Equal(t, "1", resp.Me.Id)
@@ -44,7 +44,7 @@ func TestServerError(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := failingQuery(ctx, client)
+	resp, _, err := failingQuery(ctx, client)
 	// As long as we get some response back, we should still return a full
 	// response -- and indeed in this case it should even have another field
 	// (which didn't err) set.
@@ -57,7 +57,7 @@ func TestNetworkError(t *testing.T) {
 	ctx := context.Background()
 	client := newRoundtripClient(t, "https://nothing.invalid/graphql")
 
-	resp, err := failingQuery(ctx, client)
+	resp, _, err := failingQuery(ctx, client)
 	// As we guarantee in the README, even on network error you always get a
 	// non-nil response; this is so you can write e.g.
 	//	resp, err := failingQuery(ctx)
@@ -82,19 +82,34 @@ func TestVariables(t *testing.T) {
 	// worry about it.
 	client := graphql.NewClient(server.URL, http.DefaultClient)
 
-	resp, err := queryWithVariables(ctx, client, "2")
+	resp, _, err := queryWithVariables(ctx, client, "2")
 	require.NoError(t, err)
 
 	assert.Equal(t, "2", resp.User.Id)
 	assert.Equal(t, "Raven", resp.User.Name)
 	assert.Equal(t, -1, resp.User.LuckyNumber)
 
-	resp, err = queryWithVariables(ctx, client, "374892379482379")
+	resp, _, err = queryWithVariables(ctx, client, "374892379482379")
 	require.NoError(t, err)
 
 	assert.Zero(t, resp.User)
 }
 
+func TestExtensions(t *testing.T) {
+	_ = `# @genqlient
+	query simpleQueryExt { me { id name luckyNumber } }`
+
+	ctx := context.Background()
+	server := server.RunServer()
+	defer server.Close()
+	client := newRoundtripClient(t, server.URL)
+
+	_, extensions, err := simpleQueryExt(ctx, client)
+	require.NoError(t, err)
+	assert.NotNil(t, extensions)
+	assert.Equal(t, extensions["foobar"], "test")
+}
+
 func TestOmitempty(t *testing.T) {
 	_ = `# @genqlient(omitempty: true)
 	query queryWithOmitempty($id: ID) {
@@ -106,7 +121,7 @@ func TestOmitempty(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithOmitempty(ctx, client, "2")
+	resp, _, err := queryWithOmitempty(ctx, client, "2")
 	require.NoError(t, err)
 
 	assert.Equal(t, "2", resp.User.Id)
@@ -114,7 +129,7 @@ func TestOmitempty(t *testing.T) {
 	assert.Equal(t, -1, resp.User.LuckyNumber)
 
 	// should return default user, not the user with ID ""
-	resp, err = queryWithOmitempty(ctx, client, "")
+	resp, _, err = queryWithOmitempty(ctx, client, "")
 	require.NoError(t, err)
 
 	assert.Equal(t, "1", resp.User.Id)
@@ -133,7 +148,7 @@ func TestCustomMarshal(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithCustomMarshal(ctx, client,
+	resp, _, err := queryWithCustomMarshal(ctx, client,
 		time.Date(2025, time.January, 1, 12, 34, 56, 789, time.UTC))
 	require.NoError(t, err)
 
@@ -145,7 +160,7 @@ func TestCustomMarshal(t *testing.T) {
 		time.Date(2025, time.January, 1, 0, 0, 0, 0, time.UTC),
 		user.Birthdate)
 
-	resp, err = queryWithCustomMarshal(ctx, client,
+	resp, _, err = queryWithCustomMarshal(ctx, client,
 		time.Date(2021, time.January, 1, 12, 34, 56, 789, time.UTC))
 	require.NoError(t, err)
 	assert.Len(t, resp.UsersBornOn, 0)
@@ -162,7 +177,7 @@ func TestCustomMarshalSlice(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithCustomMarshalSlice(ctx, client,
+	resp, _, err := queryWithCustomMarshalSlice(ctx, client,
 		[]time.Time{time.Date(2025, time.January, 1, 12, 34, 56, 789, time.UTC)})
 	require.NoError(t, err)
 
@@ -174,7 +189,7 @@ func TestCustomMarshalSlice(t *testing.T) {
 		time.Date(2025, time.January, 1, 0, 0, 0, 0, time.UTC),
 		user.Birthdate)
 
-	resp, err = queryWithCustomMarshalSlice(ctx, client,
+	resp, _, err = queryWithCustomMarshalSlice(ctx, client,
 		[]time.Time{time.Date(2021, time.January, 1, 12, 34, 56, 789, time.UTC)})
 	require.NoError(t, err)
 	assert.Len(t, resp.UsersBornOnDates, 0)
@@ -197,7 +212,7 @@ func TestCustomMarshalOptional(t *testing.T) {
 	client := newRoundtripClient(t, server.URL)
 
 	date := time.Date(2025, time.January, 1, 12, 34, 56, 789, time.UTC)
-	resp, err := queryWithCustomMarshalOptional(ctx, client, &date, nil)
+	resp, _, err := queryWithCustomMarshalOptional(ctx, client, &date, nil)
 	require.NoError(t, err)
 
 	assert.Len(t, resp.UserSearch, 1)
@@ -209,7 +224,7 @@ func TestCustomMarshalOptional(t *testing.T) {
 		user.Birthdate)
 
 	id := "2"
-	resp, err = queryWithCustomMarshalOptional(ctx, client, nil, &id)
+	resp, _, err = queryWithCustomMarshalOptional(ctx, client, nil, &id)
 	require.NoError(t, err)
 	assert.Len(t, resp.UserSearch, 1)
 	user = resp.UserSearch[0]
@@ -230,7 +245,7 @@ func TestInterfaceNoFragments(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithInterfaceNoFragments(ctx, client, "1")
+	resp, _, err := queryWithInterfaceNoFragments(ctx, client, "1")
 	require.NoError(t, err)
 
 	// We should get the following response:
@@ -250,7 +265,7 @@ func TestInterfaceNoFragments(t *testing.T) {
 	assert.Equal(t, "1", user.Id)
 	assert.Equal(t, "Yours Truly", user.Name)
 
-	resp, err = queryWithInterfaceNoFragments(ctx, client, "3")
+	resp, _, err = queryWithInterfaceNoFragments(ctx, client, "3")
 	require.NoError(t, err)
 
 	// We should get the following response:
@@ -269,7 +284,7 @@ func TestInterfaceNoFragments(t *testing.T) {
 	assert.Equal(t, "3", animal.Id)
 	assert.Equal(t, "Fido", animal.Name)
 
-	resp, err = queryWithInterfaceNoFragments(ctx, client, "4757233945723")
+	resp, _, err = queryWithInterfaceNoFragments(ctx, client, "4757233945723")
 	require.NoError(t, err)
 
 	// We should get the following response:
@@ -293,7 +308,7 @@ func TestInterfaceListField(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithInterfaceListField(ctx, client,
+	resp, _, err := queryWithInterfaceListField(ctx, client,
 		[]string{"1", "3", "12847394823"})
 	require.NoError(t, err)
 
@@ -340,7 +355,7 @@ func TestInterfaceListPointerField(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithInterfaceListPointerField(ctx, client,
+	resp, _, err := queryWithInterfaceListPointerField(ctx, client,
 		[]string{"1", "3", "12847394823"})
 	require.NoError(t, err)
 
@@ -394,7 +409,7 @@ func TestFragments(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithFragments(ctx, client, []string{"1", "3", "12847394823"})
+	resp, _, err := queryWithFragments(ctx, client, []string{"1", "3", "12847394823"})
 	require.NoError(t, err)
 
 	require.Len(t, resp.Beings, 3)
@@ -487,7 +502,7 @@ func TestNamedFragments(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithNamedFragments(ctx, client, []string{"1", "3", "12847394823"})
+	resp, _, err := queryWithNamedFragments(ctx, client, []string{"1", "3", "12847394823"})
 	require.NoError(t, err)
 
 	require.Len(t, resp.Beings, 3)
@@ -616,7 +631,7 @@ func TestFlatten(t *testing.T) {
 	defer server.Close()
 	client := newRoundtripClient(t, server.URL)
 
-	resp, err := queryWithFlatten(ctx, client, []string{"1", "3", "12847394823"})
+	resp, _, err := queryWithFlatten(ctx, client, []string{"1", "3", "12847394823"})
 	require.NoError(t, err)
 
 	require.Len(t, resp.Beings, 3)