From 3ceaa18941bfa5cfd26e1d1eaae499050f72c91d Mon Sep 17 00:00:00 2001 From: Adam Scarr Date: Mon, 23 Apr 2018 10:29:37 +1000 Subject: [PATCH 1/2] add request middleware --- .gitignore | 2 ++ .gometalinter.json | 2 +- codegen/templates/data.go | 4 +-- codegen/templates/field.gotpl | 2 +- codegen/templates/generated.gotpl | 44 ++++++++++++++---------- example/chat/generated.go | 48 +++++++++++++++----------- example/chat/package.json | 2 ++ example/chat/server/server.go | 43 ++++++++++++++++++++++++ example/dataloader/generated.go | 21 +++++++----- example/dataloader/server/server.go | 6 +++- example/scalars/generated.go | 19 ++++++----- example/selection/generated.go | 13 +++++--- example/starwars/generated.go | 52 ++++++++++++++++------------- example/starwars/server/server.go | 2 +- example/todo/generated.go | 32 ++++++++++-------- graphql/context.go | 11 +++--- handler/graphql.go | 41 ++++++++++++++++++++--- handler/websocket.go | 12 ++++--- opentracing/opentracing.go | 18 ++++++++-- test/generated.go | 27 ++++++++------- test/resolvers_test.go | 5 ++- 21 files changed, 274 insertions(+), 132 deletions(-) diff --git a/.gitignore b/.gitignore index 10ed19500d4..e726518406a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /internal/tests/testdata/graphql-js /vendor /docs/public +/example/chat/node_modules +/example/chat/package-lock.json diff --git a/.gometalinter.json b/.gometalinter.json index ab1c96e4fbd..b8162c837ad 100644 --- a/.gometalinter.json +++ b/.gometalinter.json @@ -1,6 +1,6 @@ { "sort": ["path"], - "Deadline": "2m", + "Deadline": "5m", "Linters": { "errcheck": { "Command": "errcheck -abspath -ignore '[rR]ead|[wW]rite|Close'", diff --git a/codegen/templates/data.go b/codegen/templates/data.go index 69c49f59ac1..7e3bcd09f29 100644 --- a/codegen/templates/data.go +++ b/codegen/templates/data.go @@ -2,8 +2,8 @@ package templates var data = map[string]string{ "args.gotpl": "\t{{- if . }}args := map[string]interface{}{} {{end}}\n\t{{- range $i, $arg := . }}\n\t\tvar arg{{$i}} {{$arg.Signature }}\n\t\tif tmp, ok := field.Args[{{$arg.GQLName|quote}}]; ok {\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\tec.Error(err)\n\t\t\t\t{{- if $arg.Object.Stream }}\n\t\t\t\t\treturn nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t{{- end }}\n\t\t\t}\n\t\t} {{ if $arg.Default }} else {\n\t\t\tvar tmp interface{} = {{ $arg.Default | dump }}\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\tec.Error(err)\n\t\t\t\t{{- if $arg.Object.Stream }}\n\t\t\t\t\treturn nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\t\t{{end }}\n\t\targs[{{$arg.GQLName|quote}}] = arg{{$i}}\n\t{{- end -}}\n", - "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field})\n\t\tresults, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\tif err != nil {\n\t\t\tec.Error(err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\n\t\t{{- if $field.IsConcurrent }}\n\t\t\treturn graphql.Defer(func() (ret graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tuserErr := ec.Recover(r)\n\t\t\t\t\t\tec.Error(userErr)\n\t\t\t\t\t\tret = graphql.Null\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t{{- end }}\n\n\t\t\t{{- if $field.GoVarName }}\n\t\t\t\tres := obj.{{$field.GoVarName}}\n\t\t\t{{- else if $field.GoMethodName }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\tres := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t{{- else }}\n\t\t\t\t\tres, err := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(err)\n\t\t\t\t\t\treturn graphql.Null\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- else }}\n\t\t\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\t\t\tField: field,\n\t\t\t\t})\n\t\t\t\tresTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tec.Error(err)\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tif resTmp == nil {\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tres := resTmp.({{$field.Signature}})\n\t\t\t{{- end }}\n\t\t\t{{ $field.WriteJson }}\n\t\t{{- if $field.IsConcurrent }}\n\t\t\t})\n\t\t{{- end }}\n\t}\n{{ end }}\n", - "generated.gotpl": "// This file was generated by github.com/vektah/gqlgen, DO NOT EDIT\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\nfunc MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema {\n\treturn &executableSchema{resolvers: resolvers}\n}\n\ntype Resolvers interface {\n{{- range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{ $field.ResolverDeclaration }}\n\t{{ end }}\n{{- end }}\n}\n\ntype executableSchema struct {\n\tresolvers Resolvers\n}\n\nfunc (e *executableSchema) Schema() *schema.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .QueryRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tdata := ec._{{.QueryRoot.GQLType}}(ctx, op.Selections)\n\t\tvar buf bytes.Buffer\n\t\tdata.MarshalGQL(&buf)\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf.Bytes(),\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn &graphql.Response{Errors: []*errors.QueryError{ {Message: \"queries are not supported\"} }}\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .MutationRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tdata := ec._{{.MutationRoot.GQLType}}(ctx, op.Selections)\n\t\tvar buf bytes.Buffer\n\t\tdata.MarshalGQL(&buf)\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf.Bytes(),\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn &graphql.Response{Errors: []*errors.QueryError{ {Message: \"mutations are not supported\"} }}\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Subscription(ctx context.Context, op *query.Operation) func() *graphql.Response {\n\t{{- if .SubscriptionRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tnext := ec._{{.SubscriptionRoot.GQLType}}(ctx, op.Selections)\n\t\tif ec.Errors != nil {\n\t\t\treturn graphql.OneShot(&graphql.Response{Data: []byte(\"null\"), Errors: ec.Errors})\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\treturn func() *graphql.Response {\n\t\t\tbuf.Reset()\n\t\t\tdata := next()\n\t\t\tif data == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tdata.MarshalGQL(&buf)\n\n\t\t\terrs := ec.Errors\n\t\t\tec.Errors = nil\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf.Bytes(),\n\t\t\t\tErrors: errs,\n\t\t\t}\n\t\t}\n\t{{- else }}\n\t\treturn graphql.OneShot(&graphql.Response{Errors: []*errors.QueryError{ {Message: \"subscriptions are not supported\"} }})\n\t{{- end }}\n}\n\ntype executionContext struct {\n\t*graphql.RequestContext\n\n\tresolvers Resolvers\n}\n\n{{- range $object := .Objects }}\n\t{{ template \"object.gotpl\" $object }}\n\n\t{{- range $field := $object.Fields }}\n\t\t{{ template \"field.gotpl\" $field }}\n\t{{ end }}\n{{- end}}\n\n{{- range $interface := .Interfaces }}\n\t{{ template \"interface.gotpl\" $interface }}\n{{- end }}\n\n{{- range $input := .Inputs }}\n\t{{ template \"input.gotpl\" $input }}\n{{- end }}\n\nfunc (ec *executionContext) introspectSchema() *introspection.Schema {\n\treturn introspection.WrapSchema(parsedSchema)\n}\n\nfunc (ec *executionContext) introspectType(name string) *introspection.Type {\n\tt := parsedSchema.Resolve(name)\n\tif t == nil {\n\t\treturn nil\n\t}\n\treturn introspection.WrapType(t)\n}\n\nvar parsedSchema = schema.MustParse({{.SchemaRaw|rawQuote}})\n", + "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field})\n\t\tresults, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\tif err != nil {\n\t\t\tec.Error(err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\n\t\t{{- if $field.IsConcurrent }}\n\t\t\treturn graphql.Defer(func() (ret graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tuserErr := ec.Recover(r)\n\t\t\t\t\t\tec.Error(userErr)\n\t\t\t\t\t\tret = graphql.Null\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t{{- end }}\n\n\t\t\t{{- if $field.GoVarName }}\n\t\t\t\tres := obj.{{$field.GoVarName}}\n\t\t\t{{- else if $field.GoMethodName }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\tres := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t{{- else }}\n\t\t\t\t\tres, err := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(err)\n\t\t\t\t\t\treturn graphql.Null\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- else }}\n\t\t\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\t\t\tField: field,\n\t\t\t\t})\n\t\t\t\tresTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tec.Error(err)\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tif resTmp == nil {\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tres := resTmp.({{$field.Signature}})\n\t\t\t{{- end }}\n\t\t\t{{ $field.WriteJson }}\n\t\t{{- if $field.IsConcurrent }}\n\t\t\t})\n\t\t{{- end }}\n\t}\n{{ end }}\n", + "generated.gotpl": "// This file was generated by github.com/vektah/gqlgen, DO NOT EDIT\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\nfunc MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema {\n\treturn &executableSchema{resolvers: resolvers}\n}\n\ntype Resolvers interface {\n{{- range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{ $field.ResolverDeclaration }}\n\t{{ end }}\n{{- end }}\n}\n\ntype executableSchema struct {\n\tresolvers Resolvers\n}\n\nfunc (e *executableSchema) Schema() *schema.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .QueryRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.QueryRoot.GQLType}}(ctx, op.Selections)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn &graphql.Response{Errors: []*errors.QueryError{ {Message: \"queries are not supported\"} }}\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .MutationRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.MutationRoot.GQLType}}(ctx, op.Selections)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn &graphql.Response{Errors: []*errors.QueryError{ {Message: \"mutations are not supported\"} }}\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Subscription(ctx context.Context, op *query.Operation) func() *graphql.Response {\n\t{{- if .SubscriptionRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tnext := ec._{{.SubscriptionRoot.GQLType}}(ctx, op.Selections)\n\t\tif ec.Errors != nil {\n\t\t\treturn graphql.OneShot(&graphql.Response{Data: []byte(\"null\"), Errors: ec.Errors})\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\treturn func() *graphql.Response {\n\t\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\t\tbuf.Reset()\n\t\t\t\tdata := next()\n\n\t\t\t\tif data == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tdata.MarshalGQL(&buf)\n\t\t\t\treturn buf.Bytes()\n\t\t\t})\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf,\n\t\t\t\tErrors: ec.Errors,\n\t\t\t}\n\t\t}\n\t{{- else }}\n\t\treturn graphql.OneShot(&graphql.Response{Errors: []*errors.QueryError{ {Message: \"subscriptions are not supported\"} }})\n\t{{- end }}\n}\n\ntype executionContext struct {\n\t*graphql.RequestContext\n\n\tresolvers Resolvers\n}\n\n{{- range $object := .Objects }}\n\t{{ template \"object.gotpl\" $object }}\n\n\t{{- range $field := $object.Fields }}\n\t\t{{ template \"field.gotpl\" $field }}\n\t{{ end }}\n{{- end}}\n\n{{- range $interface := .Interfaces }}\n\t{{ template \"interface.gotpl\" $interface }}\n{{- end }}\n\n{{- range $input := .Inputs }}\n\t{{ template \"input.gotpl\" $input }}\n{{- end }}\n\nfunc (ec *executionContext) introspectSchema() *introspection.Schema {\n\treturn introspection.WrapSchema(parsedSchema)\n}\n\nfunc (ec *executionContext) introspectType(name string) *introspection.Type {\n\tt := parsedSchema.Resolve(name)\n\tif t == nil {\n\t\treturn nil\n\t}\n\treturn introspection.WrapType(t)\n}\n\nvar parsedSchema = schema.MustParse({{.SchemaRaw|rawQuote}})\n", "input.gotpl": "\t{{- if .IsMarshaled }}\n\tfunc Unmarshal{{ .GQLType }}(v interface{}) ({{.FullName}}, error) {\n\t\tvar it {{.FullName}}\n\n\t\tfor k, v := range v.(map[string]interface{}) {\n\t\t\tswitch k {\n\t\t\t{{- range $field := .Fields }}\n\t\t\tcase {{$field.GQLName|quote}}:\n\t\t\t\tvar err error\n\t\t\t\t{{ $field.Unmarshal (print \"it.\" $field.GoVarName) \"v\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn it, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\n\t\treturn it, nil\n\t}\n\t{{- end }}\n", "interface.gotpl": "{{- $interface := . }}\n\nfunc (ec *executionContext) _{{$interface.GQLType}}(ctx context.Context, sel []query.Selection, obj *{{$interface.FullName}}) graphql.Marshaler {\n\tswitch obj := (*obj).(type) {\n\tcase nil:\n\t\treturn graphql.Null\n\t{{- range $implementor := $interface.Implementors }}\n\t\t{{- if $implementor.ValueReceiver }}\n\t\t\tcase {{$implementor.FullName}}:\n\t\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, &obj)\n\t\t{{- end}}\n\t\tcase *{{$implementor.FullName}}:\n\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, obj)\n\t{{- end }}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected type %T\", obj))\n\t}\n}\n", "models.gotpl": "// This file was generated by github.com/vektah/gqlgen, DO NOT EDIT\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\n{{ range $model := .Models }}\n\t{{- if .IsInterface }}\n\t\ttype {{.GoType}} interface {}\n\t{{- else }}\n\t\ttype {{.GoType}} struct {\n\t\t\t{{- range $field := .Fields }}\n\t\t\t\t{{- if $field.GoVarName }}\n\t\t\t\t\t{{ $field.GoVarName }} {{$field.Signature}}\n\t\t\t\t{{- else }}\n\t\t\t\t\t{{ $field.GoFKName }} {{$field.GoFKType}}\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t}\n\t{{- end }}\n{{- end}}\n\n{{ range $enum := .Enums }}\n\ttype {{.GoType}} string\n\tconst (\n\t{{ range $value := .Values }}\n\t\t{{$enum.GoType}}{{ .Name|toCamel }} {{$enum.GoType}} = {{.Name|quote}} {{with .Description}} // {{.}} {{end}}\n\t{{- end }}\n\t)\n\n\tfunc (e {{.GoType}}) IsValid() bool {\n\t\tswitch e {\n\t\tcase {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ $enum.GoType }}{{ $element.Name|toCamel }}{{end}}:\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunc (e {{.GoType}}) String() string {\n\t\treturn string(e)\n\t}\n\n\tfunc (e *{{.GoType}}) UnmarshalGQL(v interface{}) error {\n\t\tstr, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"enums must be strings\")\n\t\t}\n\n\t\t*e = {{.GoType}}(str)\n\t\tif !e.IsValid() {\n\t\t\treturn fmt.Errorf(\"%s is not a valid {{.GQLType}}\", str)\n\t\t}\n\t\treturn nil\n\t}\n\n\tfunc (e {{.GoType}}) MarshalGQL(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(e.String()))\n\t}\n\n{{- end }}\n", diff --git a/codegen/templates/field.gotpl b/codegen/templates/field.gotpl index 9ab270b572e..e77e71986a8 100644 --- a/codegen/templates/field.gotpl +++ b/codegen/templates/field.gotpl @@ -53,7 +53,7 @@ Args: {{if $field.Args }}args{{else}}nil{{end}}, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }}) }) if err != nil { diff --git a/codegen/templates/generated.gotpl b/codegen/templates/generated.gotpl index cc8a4ba92c0..5ae2120cd7b 100644 --- a/codegen/templates/generated.gotpl +++ b/codegen/templates/generated.gotpl @@ -32,12 +32,15 @@ func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *grap {{- if .QueryRoot }} ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._{{.QueryRoot.GQLType}}(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._{{.QueryRoot.GQLType}}(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } {{- else }} @@ -49,12 +52,15 @@ func (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *g {{- if .MutationRoot }} ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._{{.MutationRoot.GQLType}}(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._{{.MutationRoot.GQLType}}(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } {{- else }} @@ -73,18 +79,20 @@ func (e *executableSchema) Subscription(ctx context.Context, op *query.Operation var buf bytes.Buffer return func() *graphql.Response { - buf.Reset() - data := next() - if data == nil { - return nil - } - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + buf.Reset() + data := next() + + if data == nil { + return nil + } + data.MarshalGQL(&buf) + return buf.Bytes() + }) - errs := ec.Errors - ec.Errors = nil return &graphql.Response{ - Data: buf.Bytes(), - Errors: errs, + Data: buf, + Errors: ec.Errors, } } {{- else }} diff --git a/example/chat/generated.go b/example/chat/generated.go index 6bf8922d3b1..d616f24ccdb 100644 --- a/example/chat/generated.go +++ b/example/chat/generated.go @@ -35,12 +35,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Query(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Query(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -48,12 +51,15 @@ func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *grap func (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Mutation(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Mutation(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -68,18 +74,20 @@ func (e *executableSchema) Subscription(ctx context.Context, op *query.Operation var buf bytes.Buffer return func() *graphql.Response { - buf.Reset() - data := next() - if data == nil { - return nil - } - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + buf.Reset() + data := next() + + if data == nil { + return nil + } + data.MarshalGQL(&buf) + return buf.Bytes() + }) - errs := ec.Errors - ec.Errors = nil return &graphql.Response{ - Data: buf.Bytes(), - Errors: errs, + Data: buf, + Errors: ec.Errors, } } } @@ -235,7 +243,7 @@ func (ec *executionContext) _Mutation_post(ctx context.Context, field graphql.Co Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Mutation_post(rctx, args["text"].(string), args["username"].(string), args["roomName"].(string)) }) if err != nil { @@ -300,7 +308,7 @@ func (ec *executionContext) _Query_room(ctx context.Context, field graphql.Colle Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_room(rctx, args["name"].(string)) }) if err != nil { diff --git a/example/chat/package.json b/example/chat/package.json index 6b3c0346d90..119c7ea2ed1 100644 --- a/example/chat/package.json +++ b/example/chat/package.json @@ -5,6 +5,8 @@ "dependencies": { "apollo-cache-inmemory": "^1.1.9", "apollo-client": "^2.2.5", + "graphql-tag": "^2.9.1", + "graphql": "^0.13.2", "react": "^16.2.0", "react-apollo": "^2.1.0-beta.2", "react-dom": "^16.2.0", diff --git a/example/chat/server/server.go b/example/chat/server/server.go index 2bab154b85e..1a163996378 100644 --- a/example/chat/server/server.go +++ b/example/chat/server/server.go @@ -3,15 +3,26 @@ package main import ( "log" "net/http" + "net/url" + "time" "github.com/gorilla/websocket" + "github.com/opentracing/opentracing-go" "github.com/vektah/gqlgen/example/chat" "github.com/vektah/gqlgen/handler" + gqlopentracing "github.com/vektah/gqlgen/opentracing" + "sourcegraph.com/sourcegraph/appdash" + appdashtracer "sourcegraph.com/sourcegraph/appdash/opentracing" + "sourcegraph.com/sourcegraph/appdash/traceapp" ) func main() { + startAppdashServer() + http.Handle("/", handler.Playground("Todo", "/query")) http.Handle("/query", handler.GraphQL(chat.MakeExecutableSchema(chat.New()), + handler.ResolverMiddleware(gqlopentracing.ResolverMiddleware()), + handler.RequestMiddleware(gqlopentracing.RequestMiddleware()), handler.WebsocketUpgrader(websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true @@ -20,3 +31,35 @@ func main() { ) log.Fatal(http.ListenAndServe(":8085", nil)) } + +func startAppdashServer() opentracing.Tracer { + memStore := appdash.NewMemoryStore() + store := &appdash.RecentStore{ + MinEvictAge: 5 * time.Minute, + DeleteStore: memStore, + } + + url, err := url.Parse("http://localhost:8700") + if err != nil { + log.Fatal(err) + } + tapp, err := traceapp.New(nil, url) + if err != nil { + log.Fatal(err) + } + tapp.Store = store + tapp.Queryer = memStore + + go func() { + log.Fatal(http.ListenAndServe(":8700", tapp)) + }() + tapp.Store = store + tapp.Queryer = memStore + + collector := appdash.NewLocalCollector(store) + tracer := appdashtracer.NewTracer(collector) + opentracing.InitGlobalTracer(tracer) + + log.Println("Appdash web UI running on HTTP :8700") + return tracer +} diff --git a/example/dataloader/generated.go b/example/dataloader/generated.go index b54d6524e7f..ac5abd33d7c 100644 --- a/example/dataloader/generated.go +++ b/example/dataloader/generated.go @@ -38,12 +38,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Query(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Query(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -155,7 +158,7 @@ func (ec *executionContext) _Customer_address(ctx context.Context, field graphql Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Customer_address(rctx, obj) }) if err != nil { @@ -187,7 +190,7 @@ func (ec *executionContext) _Customer_orders(ctx context.Context, field graphql. Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Customer_orders(rctx, obj) }) if err != nil { @@ -290,7 +293,7 @@ func (ec *executionContext) _Order_items(ctx context.Context, field graphql.Coll Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Order_items(rctx, obj) }) if err != nil { @@ -351,7 +354,7 @@ func (ec *executionContext) _Query_customers(ctx context.Context, field graphql. Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_customers(rctx) }) if err != nil { @@ -403,7 +406,7 @@ func (ec *executionContext) _Query_torture(ctx context.Context, field graphql.Co Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_torture(rctx, args["customerIds"].([][]int)) }) if err != nil { diff --git a/example/dataloader/server/server.go b/example/dataloader/server/server.go index c016c5aebb7..22b3b214e51 100644 --- a/example/dataloader/server/server.go +++ b/example/dataloader/server/server.go @@ -25,7 +25,11 @@ func main() { router.Use(dataloader.LoaderMiddleware) router.Handle("/", handler.Playground("Dataloader", "/query")) - router.Handle("/query", handler.GraphQL(dataloader.MakeExecutableSchema(&dataloader.Resolver{}), handler.Use(gqlopentracing.Middleware()))) + router.Handle("/query", handler.GraphQL( + dataloader.MakeExecutableSchema(&dataloader.Resolver{}), + handler.ResolverMiddleware(gqlopentracing.ResolverMiddleware()), + handler.RequestMiddleware(gqlopentracing.RequestMiddleware()), + )) log.Println("connect to http://localhost:8082/ for graphql playground") log.Fatal(http.ListenAndServe(":8082", router)) diff --git a/example/scalars/generated.go b/example/scalars/generated.go index d49ad2b1b26..2e5dbdc1a85 100644 --- a/example/scalars/generated.go +++ b/example/scalars/generated.go @@ -39,12 +39,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Query(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Query(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -153,7 +156,7 @@ func (ec *executionContext) _Query_user(ctx context.Context, field graphql.Colle Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_user(rctx, args["id"].(external.ObjectID)) }) if err != nil { @@ -205,7 +208,7 @@ func (ec *executionContext) _Query_search(ctx context.Context, field graphql.Col Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_search(rctx, args["input"].(SearchArgs)) }) if err != nil { @@ -321,7 +324,7 @@ func (ec *executionContext) _User_primitiveResolver(ctx context.Context, field g Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.User_primitiveResolver(rctx, obj) }) if err != nil { @@ -350,7 +353,7 @@ func (ec *executionContext) _User_customResolver(ctx context.Context, field grap Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.User_customResolver(rctx, obj) }) if err != nil { diff --git a/example/selection/generated.go b/example/selection/generated.go index 16951bd8e9e..a9f8ecb8308 100644 --- a/example/selection/generated.go +++ b/example/selection/generated.go @@ -34,12 +34,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Query(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Query(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -210,7 +213,7 @@ func (ec *executionContext) _Query_events(ctx context.Context, field graphql.Col Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_events(rctx) }) if err != nil { diff --git a/example/starwars/generated.go b/example/starwars/generated.go index 6b2d115e11e..8228de453c6 100644 --- a/example/starwars/generated.go +++ b/example/starwars/generated.go @@ -53,12 +53,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Query(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Query(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -66,12 +69,15 @@ func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *grap func (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Mutation(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Mutation(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -142,7 +148,7 @@ func (ec *executionContext) _Droid_friends(ctx context.Context, field graphql.Co Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Droid_friends(rctx, obj) }) if err != nil { @@ -206,7 +212,7 @@ func (ec *executionContext) _Droid_friendsConnection(ctx context.Context, field Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Droid_friendsConnection(rctx, obj, args["first"].(*int), args["after"].(*string)) }) if err != nil { @@ -282,7 +288,7 @@ func (ec *executionContext) _FriendsConnection_edges(ctx context.Context, field Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.FriendsConnection_edges(rctx, obj) }) if err != nil { @@ -315,7 +321,7 @@ func (ec *executionContext) _FriendsConnection_friends(ctx context.Context, fiel Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.FriendsConnection_friends(rctx, obj) }) if err != nil { @@ -463,7 +469,7 @@ func (ec *executionContext) _Human_friends(ctx context.Context, field graphql.Co Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Human_friends(rctx, obj) }) if err != nil { @@ -527,7 +533,7 @@ func (ec *executionContext) _Human_friendsConnection(ctx context.Context, field Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Human_friendsConnection(rctx, obj, args["first"].(*int), args["after"].(*string)) }) if err != nil { @@ -565,7 +571,7 @@ func (ec *executionContext) _Human_starships(ctx context.Context, field graphql. Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Human_starships(rctx, obj) }) if err != nil { @@ -633,7 +639,7 @@ func (ec *executionContext) _Mutation_createReview(ctx context.Context, field gr Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Mutation_createReview(rctx, args["episode"].(Episode), args["review"].(Review)) }) if err != nil { @@ -763,7 +769,7 @@ func (ec *executionContext) _Query_hero(ctx context.Context, field graphql.Colle Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_hero(rctx, args["episode"].(Episode)) }) if err != nil { @@ -818,7 +824,7 @@ func (ec *executionContext) _Query_reviews(ctx context.Context, field graphql.Co Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_reviews(rctx, args["episode"].(Episode), args["since"].(*time.Time)) }) if err != nil { @@ -862,7 +868,7 @@ func (ec *executionContext) _Query_search(ctx context.Context, field graphql.Col Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_search(rctx, args["text"].(string)) }) if err != nil { @@ -906,7 +912,7 @@ func (ec *executionContext) _Query_character(ctx context.Context, field graphql. Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_character(rctx, args["id"].(string)) }) if err != nil { @@ -946,7 +952,7 @@ func (ec *executionContext) _Query_droid(ctx context.Context, field graphql.Coll Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_droid(rctx, args["id"].(string)) }) if err != nil { @@ -989,7 +995,7 @@ func (ec *executionContext) _Query_human(ctx context.Context, field graphql.Coll Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_human(rctx, args["id"].(string)) }) if err != nil { @@ -1032,7 +1038,7 @@ func (ec *executionContext) _Query_starship(ctx context.Context, field graphql.C Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_starship(rctx, args["id"].(string)) }) if err != nil { diff --git a/example/starwars/server/server.go b/example/starwars/server/server.go index dc2c57d2ae4..86bdbdc5468 100644 --- a/example/starwars/server/server.go +++ b/example/starwars/server/server.go @@ -14,7 +14,7 @@ import ( func main() { http.Handle("/", handler.Playground("Starwars", "/query")) http.Handle("/query", handler.GraphQL(starwars.MakeExecutableSchema(starwars.NewResolver()), - handler.Use(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + handler.ResolverMiddleware(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { rc := graphql.GetResolverContext(ctx) fmt.Println("Entered", rc.Object, rc.Field.Name) res, err = next(ctx) diff --git a/example/todo/generated.go b/example/todo/generated.go index 8b815211d0f..8b32fcb3fb9 100644 --- a/example/todo/generated.go +++ b/example/todo/generated.go @@ -37,12 +37,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._MyQuery(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._MyQuery(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -50,12 +53,15 @@ func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *grap func (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._MyMutation(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._MyMutation(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -111,7 +117,7 @@ func (ec *executionContext) _MyMutation_createTodo(ctx context.Context, field gr Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.MyMutation_createTodo(rctx, args["todo"].(TodoInput)) }) if err != nil { @@ -152,7 +158,7 @@ func (ec *executionContext) _MyMutation_updateTodo(ctx context.Context, field gr Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.MyMutation_updateTodo(rctx, args["id"].(int), args["changes"].(map[string]interface{})) }) if err != nil { @@ -224,7 +230,7 @@ func (ec *executionContext) _MyQuery_todo(ctx context.Context, field graphql.Col Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.MyQuery_todo(rctx, args["id"].(int)) }) if err != nil { @@ -256,7 +262,7 @@ func (ec *executionContext) _MyQuery_lastTodo(ctx context.Context, field graphql Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.MyQuery_lastTodo(rctx) }) if err != nil { @@ -288,7 +294,7 @@ func (ec *executionContext) _MyQuery_todos(ctx context.Context, field graphql.Co Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.MyQuery_todos(rctx) }) if err != nil { diff --git a/graphql/context.go b/graphql/context.go index 4f2dcfcef7c..e5210a4e401 100644 --- a/graphql/context.go +++ b/graphql/context.go @@ -9,14 +9,17 @@ import ( type Resolver func(ctx context.Context) (res interface{}, err error) type ResolverMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error) +type RequestMiddleware func(ctx context.Context, next func(ctx context.Context) []byte) []byte type RequestContext struct { errors.Builder - Variables map[string]interface{} - Doc *query.Document - Recover RecoverFunc - Middleware ResolverMiddleware + RawQuery string + Variables map[string]interface{} + Doc *query.Document + Recover RecoverFunc + ResolverMiddleware ResolverMiddleware + RequestMiddleware RequestMiddleware } type key string diff --git a/handler/graphql.go b/handler/graphql.go index e15c47f35ac..44ed1924b06 100644 --- a/handler/graphql.go +++ b/handler/graphql.go @@ -25,6 +25,7 @@ type Config struct { recover graphql.RecoverFunc formatError func(error) string resolverHook graphql.ResolverMiddleware + requestHook graphql.RequestMiddleware } type Option func(cfg *Config) @@ -47,7 +48,11 @@ func FormatErrorFunc(f func(error) string) Option { } } -func Use(middleware graphql.ResolverMiddleware) Option { +// ResolverMiddleware allows you to define a function that will be called around every resolver, +// useful for tracing and logging. +// It will only be called for user defined resolvers, any direct binding to models is assumed +// to cost nothing. +func ResolverMiddleware(middleware graphql.ResolverMiddleware) Option { return func(cfg *Config) { if cfg.resolverHook == nil { cfg.resolverHook = middleware @@ -63,6 +68,24 @@ func Use(middleware graphql.ResolverMiddleware) Option { } } +// RequestMiddleware allows you to define a function that will be called around the root request, +// after the query has been parsed. This is useful for logging and tracing +func RequestMiddleware(middleware graphql.RequestMiddleware) Option { + return func(cfg *Config) { + if cfg.requestHook == nil { + cfg.requestHook = middleware + return + } + + lastResolve := cfg.requestHook + cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte { + return lastResolve(ctx, func(ctx context.Context) []byte { + return middleware(ctx, next) + }) + } + } +} + func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc { cfg := Config{ recover: graphql.DefaultRecoverFunc, @@ -82,6 +105,12 @@ func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc } } + if cfg.requestHook == nil { + cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte { + return next(ctx) + } + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions { w.Header().Set("Allow", "OPTIONS, GET, POST") @@ -136,10 +165,12 @@ func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc } ctx := graphql.WithRequestContext(r.Context(), &graphql.RequestContext{ - Doc: doc, - Variables: reqParams.Variables, - Recover: cfg.recover, - Middleware: cfg.resolverHook, + Doc: doc, + RawQuery: reqParams.Query, + Variables: reqParams.Variables, + Recover: cfg.recover, + ResolverMiddleware: cfg.resolverHook, + RequestMiddleware: cfg.requestHook, Builder: errors.Builder{ ErrorMessageFn: cfg.formatError, }, diff --git a/handler/websocket.go b/handler/websocket.go index 7662390be66..32eee24553e 100644 --- a/handler/websocket.go +++ b/handler/websocket.go @@ -49,7 +49,7 @@ func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Req "Sec-Websocket-Protocol": []string{"graphql-ws"}, }) if err != nil { - log.Printf("unable to upgrade connection to websocket %s: ", err.Error()) + log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error()) sendErrorf(w, http.StatusBadRequest, "unable to upgrade") return } @@ -156,10 +156,12 @@ func (c *wsConnection) subscribe(message *operationMessage) bool { } ctx := graphql.WithRequestContext(c.ctx, &graphql.RequestContext{ - Doc: doc, - Variables: reqParams.Variables, - Recover: c.cfg.recover, - Middleware: c.cfg.resolverHook, + Doc: doc, + Variables: reqParams.Variables, + RawQuery: reqParams.Query, + Recover: c.cfg.recover, + ResolverMiddleware: c.cfg.resolverHook, + RequestMiddleware: c.cfg.requestHook, Builder: errors.Builder{ ErrorMessageFn: c.cfg.formatError, }, diff --git a/opentracing/opentracing.go b/opentracing/opentracing.go index d7699547c18..ddb98f7ae05 100644 --- a/opentracing/opentracing.go +++ b/opentracing/opentracing.go @@ -10,16 +10,14 @@ import ( "github.com/vektah/gqlgen/graphql" ) -func Middleware() graphql.ResolverMiddleware { +func ResolverMiddleware() graphql.ResolverMiddleware { return func(ctx context.Context, next graphql.Resolver) (interface{}, error) { rctx := graphql.GetResolverContext(ctx) - span, ctx := opentracing.StartSpanFromContext(ctx, rctx.Object+"_"+rctx.Field.Name, opentracing.Tag{Key: "resolver.object", Value: rctx.Object}, opentracing.Tag{Key: "resolver.field", Value: rctx.Field.Name}, ) defer span.Finish() - ext.SpanKind.Set(span, "server") ext.Component.Set(span, "gqlgen") @@ -37,3 +35,17 @@ func Middleware() graphql.ResolverMiddleware { return res, err } } + +func RequestMiddleware() graphql.RequestMiddleware { + return func(ctx context.Context, next func(ctx context.Context) []byte) []byte { + requestContext := graphql.GetRequestContext(ctx) + span, ctx := opentracing.StartSpanFromContext(ctx, requestContext.RawQuery) + defer span.Finish() + ext.SpanKind.Set(span, "server") + ext.Component.Set(span, "gqlgen") + + res := next(ctx) + + return res + } +} diff --git a/test/generated.go b/test/generated.go index 73771099c41..d0ea1ae1735 100644 --- a/test/generated.go +++ b/test/generated.go @@ -44,12 +44,15 @@ func (e *executableSchema) Schema() *schema.Schema { func (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response { ec := executionContext{graphql.GetRequestContext(ctx), e.resolvers} - data := ec._Query(ctx, op.Selections) - var buf bytes.Buffer - data.MarshalGQL(&buf) + buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + data := ec._Query(ctx, op.Selections) + var buf bytes.Buffer + data.MarshalGQL(&buf) + return buf.Bytes() + }) return &graphql.Response{ - Data: buf.Bytes(), + Data: buf, Errors: ec.Errors, } } @@ -219,7 +222,7 @@ func (ec *executionContext) _OuterObject_inner(ctx context.Context, field graphq Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.OuterObject_inner(rctx, obj) }) if err != nil { @@ -322,7 +325,7 @@ func (ec *executionContext) _Query_nestedInputs(ctx context.Context, field graph Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_nestedInputs(rctx, args["input"].([][]models.OuterInput)) }) if err != nil { @@ -354,7 +357,7 @@ func (ec *executionContext) _Query_nestedOutputs(ctx context.Context, field grap Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_nestedOutputs(rctx) }) if err != nil { @@ -393,7 +396,7 @@ func (ec *executionContext) _Query_shapes(ctx context.Context, field graphql.Col Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_shapes(rctx) }) if err != nil { @@ -442,7 +445,7 @@ func (ec *executionContext) _Query_recursive(ctx context.Context, field graphql. Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_recursive(rctx, args["input"].(*RecursiveInputSlice)) }) if err != nil { @@ -490,7 +493,7 @@ func (ec *executionContext) _Query_mapInput(ctx context.Context, field graphql.C Args: args, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_mapInput(rctx, args["input"].(*map[string]interface{})) }) if err != nil { @@ -522,7 +525,7 @@ func (ec *executionContext) _Query_collision(ctx context.Context, field graphql. Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_collision(rctx) }) if err != nil { @@ -554,7 +557,7 @@ func (ec *executionContext) _Query_invalidIdentifier(ctx context.Context, field Args: nil, Field: field, }) - resTmp, err := ec.Middleware(rctx, func(rctx context.Context) (interface{}, error) { + resTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) { return ec.resolvers.Query_invalidIdentifier(rctx) }) if err != nil { diff --git a/test/resolvers_test.go b/test/resolvers_test.go index 06fffd3fd9e..edf119e2261 100644 --- a/test/resolvers_test.go +++ b/test/resolvers_test.go @@ -71,7 +71,10 @@ func TestErrorConverter(t *testing.T) { func mkctx(doc *query.Document, errFn func(e error) string) context.Context { return graphql.WithRequestContext(context.Background(), &graphql.RequestContext{ Doc: doc, - Middleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + ResolverMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + return next(ctx) + }, + RequestMiddleware: func(ctx context.Context, next func(ctx context.Context) []byte) []byte { return next(ctx) }, Builder: gqlerrors.Builder{ From d157ac353535af70d5c235d493281fefc8111d73 Mon Sep 17 00:00:00 2001 From: Adam Scarr Date: Mon, 23 Apr 2018 10:50:28 +1000 Subject: [PATCH 2/2] Add context to recover func This makes the request and resolver contexts available during panic so that you can log the incoming query, user info etc with your bug tracker --- codegen/templates/data.go | 2 +- codegen/templates/field.gotpl | 2 +- example/chat/generated.go | 2 +- example/dataloader/generated.go | 10 +++++----- example/scalars/generated.go | 8 ++++---- example/selection/generated.go | 2 +- example/starwars/generated.go | 28 ++++++++++++++-------------- example/todo/generated.go | 6 +++--- example/todo/server/server.go | 3 ++- graphql/recovery.go | 5 +++-- handler/graphql.go | 7 +++++++ handler/websocket.go | 2 +- test/generated.go | 16 ++++++++-------- 13 files changed, 51 insertions(+), 42 deletions(-) diff --git a/codegen/templates/data.go b/codegen/templates/data.go index 7e3bcd09f29..c7b2f380d37 100644 --- a/codegen/templates/data.go +++ b/codegen/templates/data.go @@ -2,7 +2,7 @@ package templates var data = map[string]string{ "args.gotpl": "\t{{- if . }}args := map[string]interface{}{} {{end}}\n\t{{- range $i, $arg := . }}\n\t\tvar arg{{$i}} {{$arg.Signature }}\n\t\tif tmp, ok := field.Args[{{$arg.GQLName|quote}}]; ok {\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\tec.Error(err)\n\t\t\t\t{{- if $arg.Object.Stream }}\n\t\t\t\t\treturn nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t{{- end }}\n\t\t\t}\n\t\t} {{ if $arg.Default }} else {\n\t\t\tvar tmp interface{} = {{ $arg.Default | dump }}\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\tec.Error(err)\n\t\t\t\t{{- if $arg.Object.Stream }}\n\t\t\t\t\treturn nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\t\t{{end }}\n\t\targs[{{$arg.GQLName|quote}}] = arg{{$i}}\n\t{{- end -}}\n", - "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field})\n\t\tresults, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\tif err != nil {\n\t\t\tec.Error(err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\n\t\t{{- if $field.IsConcurrent }}\n\t\t\treturn graphql.Defer(func() (ret graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tuserErr := ec.Recover(r)\n\t\t\t\t\t\tec.Error(userErr)\n\t\t\t\t\t\tret = graphql.Null\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t{{- end }}\n\n\t\t\t{{- if $field.GoVarName }}\n\t\t\t\tres := obj.{{$field.GoVarName}}\n\t\t\t{{- else if $field.GoMethodName }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\tres := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t{{- else }}\n\t\t\t\t\tres, err := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(err)\n\t\t\t\t\t\treturn graphql.Null\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- else }}\n\t\t\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\t\t\tField: field,\n\t\t\t\t})\n\t\t\t\tresTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tec.Error(err)\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tif resTmp == nil {\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tres := resTmp.({{$field.Signature}})\n\t\t\t{{- end }}\n\t\t\t{{ $field.WriteJson }}\n\t\t{{- if $field.IsConcurrent }}\n\t\t\t})\n\t\t{{- end }}\n\t}\n{{ end }}\n", + "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field})\n\t\tresults, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\tif err != nil {\n\t\t\tec.Error(err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\n\t\t{{- if $field.IsConcurrent }}\n\t\t\treturn graphql.Defer(func() (ret graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tuserErr := ec.Recover(ctx, r)\n\t\t\t\t\t\tec.Error(userErr)\n\t\t\t\t\t\tret = graphql.Null\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t{{- end }}\n\n\t\t\t{{- if $field.GoVarName }}\n\t\t\t\tres := obj.{{$field.GoVarName}}\n\t\t\t{{- else if $field.GoMethodName }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\tres := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t{{- else }}\n\t\t\t\t\tres, err := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(err)\n\t\t\t\t\t\treturn graphql.Null\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- else }}\n\t\t\t\trctx := graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\t\t\tField: field,\n\t\t\t\t})\n\t\t\t\tresTmp, err := ec.ResolverMiddleware(rctx, func(rctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tec.Error(err)\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tif resTmp == nil {\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tres := resTmp.({{$field.Signature}})\n\t\t\t{{- end }}\n\t\t\t{{ $field.WriteJson }}\n\t\t{{- if $field.IsConcurrent }}\n\t\t\t})\n\t\t{{- end }}\n\t}\n{{ end }}\n", "generated.gotpl": "// This file was generated by github.com/vektah/gqlgen, DO NOT EDIT\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\nfunc MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema {\n\treturn &executableSchema{resolvers: resolvers}\n}\n\ntype Resolvers interface {\n{{- range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{ $field.ResolverDeclaration }}\n\t{{ end }}\n{{- end }}\n}\n\ntype executableSchema struct {\n\tresolvers Resolvers\n}\n\nfunc (e *executableSchema) Schema() *schema.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .QueryRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.QueryRoot.GQLType}}(ctx, op.Selections)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn &graphql.Response{Errors: []*errors.QueryError{ {Message: \"queries are not supported\"} }}\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .MutationRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.MutationRoot.GQLType}}(ctx, op.Selections)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn &graphql.Response{Errors: []*errors.QueryError{ {Message: \"mutations are not supported\"} }}\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Subscription(ctx context.Context, op *query.Operation) func() *graphql.Response {\n\t{{- if .SubscriptionRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tnext := ec._{{.SubscriptionRoot.GQLType}}(ctx, op.Selections)\n\t\tif ec.Errors != nil {\n\t\t\treturn graphql.OneShot(&graphql.Response{Data: []byte(\"null\"), Errors: ec.Errors})\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\treturn func() *graphql.Response {\n\t\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\t\tbuf.Reset()\n\t\t\t\tdata := next()\n\n\t\t\t\tif data == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tdata.MarshalGQL(&buf)\n\t\t\t\treturn buf.Bytes()\n\t\t\t})\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf,\n\t\t\t\tErrors: ec.Errors,\n\t\t\t}\n\t\t}\n\t{{- else }}\n\t\treturn graphql.OneShot(&graphql.Response{Errors: []*errors.QueryError{ {Message: \"subscriptions are not supported\"} }})\n\t{{- end }}\n}\n\ntype executionContext struct {\n\t*graphql.RequestContext\n\n\tresolvers Resolvers\n}\n\n{{- range $object := .Objects }}\n\t{{ template \"object.gotpl\" $object }}\n\n\t{{- range $field := $object.Fields }}\n\t\t{{ template \"field.gotpl\" $field }}\n\t{{ end }}\n{{- end}}\n\n{{- range $interface := .Interfaces }}\n\t{{ template \"interface.gotpl\" $interface }}\n{{- end }}\n\n{{- range $input := .Inputs }}\n\t{{ template \"input.gotpl\" $input }}\n{{- end }}\n\nfunc (ec *executionContext) introspectSchema() *introspection.Schema {\n\treturn introspection.WrapSchema(parsedSchema)\n}\n\nfunc (ec *executionContext) introspectType(name string) *introspection.Type {\n\tt := parsedSchema.Resolve(name)\n\tif t == nil {\n\t\treturn nil\n\t}\n\treturn introspection.WrapType(t)\n}\n\nvar parsedSchema = schema.MustParse({{.SchemaRaw|rawQuote}})\n", "input.gotpl": "\t{{- if .IsMarshaled }}\n\tfunc Unmarshal{{ .GQLType }}(v interface{}) ({{.FullName}}, error) {\n\t\tvar it {{.FullName}}\n\n\t\tfor k, v := range v.(map[string]interface{}) {\n\t\t\tswitch k {\n\t\t\t{{- range $field := .Fields }}\n\t\t\tcase {{$field.GQLName|quote}}:\n\t\t\t\tvar err error\n\t\t\t\t{{ $field.Unmarshal (print \"it.\" $field.GoVarName) \"v\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn it, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\n\t\treturn it, nil\n\t}\n\t{{- end }}\n", "interface.gotpl": "{{- $interface := . }}\n\nfunc (ec *executionContext) _{{$interface.GQLType}}(ctx context.Context, sel []query.Selection, obj *{{$interface.FullName}}) graphql.Marshaler {\n\tswitch obj := (*obj).(type) {\n\tcase nil:\n\t\treturn graphql.Null\n\t{{- range $implementor := $interface.Implementors }}\n\t\t{{- if $implementor.ValueReceiver }}\n\t\t\tcase {{$implementor.FullName}}:\n\t\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, &obj)\n\t\t{{- end}}\n\t\tcase *{{$implementor.FullName}}:\n\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, obj)\n\t{{- end }}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected type %T\", obj))\n\t}\n}\n", diff --git a/codegen/templates/field.gotpl b/codegen/templates/field.gotpl index e77e71986a8..4a816482219 100644 --- a/codegen/templates/field.gotpl +++ b/codegen/templates/field.gotpl @@ -28,7 +28,7 @@ return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/chat/generated.go b/example/chat/generated.go index d616f24ccdb..c0049c2dbb6 100644 --- a/example/chat/generated.go +++ b/example/chat/generated.go @@ -298,7 +298,7 @@ func (ec *executionContext) _Query_room(ctx context.Context, field graphql.Colle return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/dataloader/generated.go b/example/dataloader/generated.go index ac5abd33d7c..d2ca6c1d141 100644 --- a/example/dataloader/generated.go +++ b/example/dataloader/generated.go @@ -148,7 +148,7 @@ func (ec *executionContext) _Customer_address(ctx context.Context, field graphql return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -180,7 +180,7 @@ func (ec *executionContext) _Customer_orders(ctx context.Context, field graphql. return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -283,7 +283,7 @@ func (ec *executionContext) _Order_items(ctx context.Context, field graphql.Coll return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -344,7 +344,7 @@ func (ec *executionContext) _Query_customers(ctx context.Context, field graphql. return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -396,7 +396,7 @@ func (ec *executionContext) _Query_torture(ctx context.Context, field graphql.Co return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/scalars/generated.go b/example/scalars/generated.go index 2e5dbdc1a85..ec97af57f4e 100644 --- a/example/scalars/generated.go +++ b/example/scalars/generated.go @@ -146,7 +146,7 @@ func (ec *executionContext) _Query_user(ctx context.Context, field graphql.Colle return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -198,7 +198,7 @@ func (ec *executionContext) _Query_search(ctx context.Context, field graphql.Col return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -314,7 +314,7 @@ func (ec *executionContext) _User_primitiveResolver(ctx context.Context, field g return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -343,7 +343,7 @@ func (ec *executionContext) _User_customResolver(ctx context.Context, field grap return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/selection/generated.go b/example/selection/generated.go index a9f8ecb8308..469a5c04d89 100644 --- a/example/selection/generated.go +++ b/example/selection/generated.go @@ -203,7 +203,7 @@ func (ec *executionContext) _Query_events(ctx context.Context, field graphql.Col return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/starwars/generated.go b/example/starwars/generated.go index 8228de453c6..2e6f48449ca 100644 --- a/example/starwars/generated.go +++ b/example/starwars/generated.go @@ -138,7 +138,7 @@ func (ec *executionContext) _Droid_friends(ctx context.Context, field graphql.Co return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -202,7 +202,7 @@ func (ec *executionContext) _Droid_friendsConnection(ctx context.Context, field return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -278,7 +278,7 @@ func (ec *executionContext) _FriendsConnection_edges(ctx context.Context, field return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -311,7 +311,7 @@ func (ec *executionContext) _FriendsConnection_friends(ctx context.Context, fiel return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -459,7 +459,7 @@ func (ec *executionContext) _Human_friends(ctx context.Context, field graphql.Co return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -523,7 +523,7 @@ func (ec *executionContext) _Human_friendsConnection(ctx context.Context, field return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -561,7 +561,7 @@ func (ec *executionContext) _Human_starships(ctx context.Context, field graphql. return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -759,7 +759,7 @@ func (ec *executionContext) _Query_hero(ctx context.Context, field graphql.Colle return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -814,7 +814,7 @@ func (ec *executionContext) _Query_reviews(ctx context.Context, field graphql.Co return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -858,7 +858,7 @@ func (ec *executionContext) _Query_search(ctx context.Context, field graphql.Col return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -902,7 +902,7 @@ func (ec *executionContext) _Query_character(ctx context.Context, field graphql. return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -942,7 +942,7 @@ func (ec *executionContext) _Query_droid(ctx context.Context, field graphql.Coll return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -985,7 +985,7 @@ func (ec *executionContext) _Query_human(ctx context.Context, field graphql.Coll return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -1028,7 +1028,7 @@ func (ec *executionContext) _Query_starship(ctx context.Context, field graphql.C return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/todo/generated.go b/example/todo/generated.go index 8b32fcb3fb9..8b4769bfddf 100644 --- a/example/todo/generated.go +++ b/example/todo/generated.go @@ -220,7 +220,7 @@ func (ec *executionContext) _MyQuery_todo(ctx context.Context, field graphql.Col return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -252,7 +252,7 @@ func (ec *executionContext) _MyQuery_lastTodo(ctx context.Context, field graphql return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -284,7 +284,7 @@ func (ec *executionContext) _MyQuery_todos(ctx context.Context, field graphql.Co return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } diff --git a/example/todo/server/server.go b/example/todo/server/server.go index fa2e0f7d53b..0c824d0e795 100644 --- a/example/todo/server/server.go +++ b/example/todo/server/server.go @@ -1,6 +1,7 @@ package main import ( + "context" "errors" "log" "net/http" @@ -14,7 +15,7 @@ func main() { http.Handle("/", handler.Playground("Todo", "/query")) http.Handle("/query", handler.GraphQL( todo.MakeExecutableSchema(todo.New()), - handler.RecoverFunc(func(err interface{}) error { + handler.RecoverFunc(func(ctx context.Context, err interface{}) error { log.Printf("send this panic somewhere") debug.PrintStack() return errors.New("user message on panic") diff --git a/graphql/recovery.go b/graphql/recovery.go index 547041e1cb9..ef5c45c9911 100644 --- a/graphql/recovery.go +++ b/graphql/recovery.go @@ -1,15 +1,16 @@ package graphql import ( + "context" "errors" "fmt" "os" "runtime/debug" ) -type RecoverFunc func(err interface{}) (userMessage error) +type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error) -func DefaultRecoverFunc(err interface{}) error { +func DefaultRecoverFunc(ctx context.Context, err interface{}) error { fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr) debug.PrintStack() diff --git a/handler/graphql.go b/handler/graphql.go index 44ed1924b06..e2a6189ec8a 100644 --- a/handler/graphql.go +++ b/handler/graphql.go @@ -176,6 +176,13 @@ func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc }, }) + defer func() { + if err := recover(); err != nil { + userErr := cfg.recover(ctx, err) + sendErrorf(w, http.StatusUnprocessableEntity, userErr.Error()) + } + }() + switch op.Type { case query.Query: b, err := json.Marshal(exec.Query(ctx, op)) diff --git a/handler/websocket.go b/handler/websocket.go index 32eee24553e..92a9e598289 100644 --- a/handler/websocket.go +++ b/handler/websocket.go @@ -187,7 +187,7 @@ func (c *wsConnection) subscribe(message *operationMessage) bool { go func() { defer func() { if r := recover(); r != nil { - userErr := c.cfg.recover(r) + userErr := c.cfg.recover(ctx, r) c.sendError(message.ID, &errors.QueryError{Message: userErr.Error()}) } }() diff --git a/test/generated.go b/test/generated.go index d0ea1ae1735..c1d86e07894 100644 --- a/test/generated.go +++ b/test/generated.go @@ -212,7 +212,7 @@ func (ec *executionContext) _OuterObject_inner(ctx context.Context, field graphq return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -315,7 +315,7 @@ func (ec *executionContext) _Query_nestedInputs(ctx context.Context, field graph return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -347,7 +347,7 @@ func (ec *executionContext) _Query_nestedOutputs(ctx context.Context, field grap return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -386,7 +386,7 @@ func (ec *executionContext) _Query_shapes(ctx context.Context, field graphql.Col return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -435,7 +435,7 @@ func (ec *executionContext) _Query_recursive(ctx context.Context, field graphql. return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -483,7 +483,7 @@ func (ec *executionContext) _Query_mapInput(ctx context.Context, field graphql.C return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -515,7 +515,7 @@ func (ec *executionContext) _Query_collision(ctx context.Context, field graphql. return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null } @@ -547,7 +547,7 @@ func (ec *executionContext) _Query_invalidIdentifier(ctx context.Context, field return graphql.Defer(func() (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { - userErr := ec.Recover(r) + userErr := ec.Recover(ctx, r) ec.Error(userErr) ret = graphql.Null }