From a44685b258710d56e1ce9f2374ca7ee577d37295 Mon Sep 17 00:00:00 2001 From: "Roman A. Grigorovich" Date: Thu, 8 Dec 2022 06:34:16 +0300 Subject: [PATCH] Ability to return multiple errors from resolvers raise than add it to stack. (#2454) * Remove DO NOT EDIT Sometimes vscode warn about this while editing resolvers code. Finally the resolver's code is editable and generated at the same time. * Ability to return multiple errors from resolver. * Multiple errors return example * Fix missing import * reformat * gofmt * go generate ./... * go generate ./... * Regenerate Signed-off-by: Steve Coffman * remove trailing period Signed-off-by: Steve Coffman Signed-off-by: Steve Coffman Co-authored-by: Roman A. Grigorovich Co-authored-by: Steve Coffman --- _examples/config/schema.resolvers.go | 2 +- _examples/config/todo.resolvers.go | 2 +- _examples/config/user.resolvers.go | 2 +- .../accounts/graph/entity.resolvers.go | 2 +- .../accounts/graph/schema.resolvers.go | 2 +- .../products/graph/entity.resolvers.go | 2 +- .../products/graph/schema.resolvers.go | 2 +- .../reviews/graph/entity.resolvers.go | 2 +- .../reviews/graph/schema.resolvers.go | 2 +- docs/content/reference/errors.md | 54 +++++++++++++++++++ graphql/context_operation.go | 8 +++ .../entityresolver/entity.resolvers.go | 2 +- plugin/resolvergen/resolver.go | 2 +- 13 files changed, 73 insertions(+), 11 deletions(-) diff --git a/_examples/config/schema.resolvers.go b/_examples/config/schema.resolvers.go index 10879d3e2a..3260244495 100644 --- a/_examples/config/schema.resolvers.go +++ b/_examples/config/schema.resolvers.go @@ -2,7 +2,7 @@ package config // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/config/todo.resolvers.go b/_examples/config/todo.resolvers.go index 71dc1d16e0..1d28c30bb3 100644 --- a/_examples/config/todo.resolvers.go +++ b/_examples/config/todo.resolvers.go @@ -2,7 +2,7 @@ package config // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/config/user.resolvers.go b/_examples/config/user.resolvers.go index 915b396e1e..9e5dcbfdbb 100644 --- a/_examples/config/user.resolvers.go +++ b/_examples/config/user.resolvers.go @@ -2,7 +2,7 @@ package config // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/federation/accounts/graph/entity.resolvers.go b/_examples/federation/accounts/graph/entity.resolvers.go index df89ffce1b..3c5ecc05a5 100644 --- a/_examples/federation/accounts/graph/entity.resolvers.go +++ b/_examples/federation/accounts/graph/entity.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/federation/accounts/graph/schema.resolvers.go b/_examples/federation/accounts/graph/schema.resolvers.go index 0462d23edb..e5888fce60 100644 --- a/_examples/federation/accounts/graph/schema.resolvers.go +++ b/_examples/federation/accounts/graph/schema.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/federation/products/graph/entity.resolvers.go b/_examples/federation/products/graph/entity.resolvers.go index 528360ca01..67b10ee57d 100644 --- a/_examples/federation/products/graph/entity.resolvers.go +++ b/_examples/federation/products/graph/entity.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/federation/products/graph/schema.resolvers.go b/_examples/federation/products/graph/schema.resolvers.go index d838f0a1c5..331834596b 100644 --- a/_examples/federation/products/graph/schema.resolvers.go +++ b/_examples/federation/products/graph/schema.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/federation/reviews/graph/entity.resolvers.go b/_examples/federation/reviews/graph/entity.resolvers.go index 998358fe28..39bcf788df 100644 --- a/_examples/federation/reviews/graph/entity.resolvers.go +++ b/_examples/federation/reviews/graph/entity.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/_examples/federation/reviews/graph/schema.resolvers.go b/_examples/federation/reviews/graph/schema.resolvers.go index 250f7b5ff4..6be9e5fa65 100644 --- a/_examples/federation/reviews/graph/schema.resolvers.go +++ b/_examples/federation/reviews/graph/schema.resolvers.go @@ -2,7 +2,7 @@ package graph // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/docs/content/reference/errors.md b/docs/content/reference/errors.md index 69acbf8971..5ed68e5602 100644 --- a/docs/content/reference/errors.md +++ b/docs/content/reference/errors.md @@ -19,11 +19,13 @@ package foo import ( "context" + "errors" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/99designs/gqlgen/graphql" ) +// DoThings add errors to the stack. func (r Query) DoThings(ctx context.Context) (bool, error) { // Print a formatted string graphql.AddErrorf(ctx, "Error %d", 1) @@ -60,6 +62,58 @@ They will be returned in the same order in the response, eg: } ``` +or you can simply return multiple errors + +```go +package foo + +import ( + "context" + "errors" + + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/99designs/gqlgen/graphql" +) + +var errSomethingWrong = errors.New("some validation failed") + +// DoThingsReturnMultipleErrors collect errors and returns it if any. +func (r Query) DoThingsReturnMultipleErrors(ctx context.Context) (bool, error) { + errList := gqlerror.List{} + + // Add existing error + errList = append(errList, gqlerror.Wrap(errSomethingWrong)) + + // Create new formatted and append + errList = append(errList, gqlerror.Errorf("invalid value: %s", "invalid")) + + // Or fully customize the error and append + errList = append(errList, &gqlerror.Error{ + Path: graphql.GetPath(ctx), + Message: "A descriptive error message", + Extensions: map[string]interface{}{ + "code": "10-4", + }, + }) + + return false, errList +} +``` + +They will be returned in the same order in the response, eg: +```json +{ + "data": { + "todo": null + }, + "errors": [ + { "message": "some validation failed", "path": [ "todo" ] }, + { "message": "invalid value: invalid", "path": [ "todo" ] }, + { "message": "A descriptive error message", "path": [ "todo" ], "extensions": { "code": "10-4" } }, + ] +} +``` + ## Hooks ### The error presenter diff --git a/graphql/context_operation.go b/graphql/context_operation.go index 0518ecc6ba..e4abaee31e 100644 --- a/graphql/context_operation.go +++ b/graphql/context_operation.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" ) // Deprecated: Please update all references to OperationContext instead @@ -109,6 +110,13 @@ func (c *OperationContext) Errorf(ctx context.Context, format string, args ...in // Error sends an error to the client, passing it through the formatter. // Deprecated: use graphql.AddError(ctx, err) instead func (c *OperationContext) Error(ctx context.Context, err error) { + if errList, ok := err.(gqlerror.List); ok { + for _, e := range errList { + AddError(ctx, e) + } + return + } + AddError(ctx, err) } diff --git a/plugin/federation/testdata/entityresolver/entity.resolvers.go b/plugin/federation/testdata/entityresolver/entity.resolvers.go index 3d91559b6c..212f6d088b 100644 --- a/plugin/federation/testdata/entityresolver/entity.resolvers.go +++ b/plugin/federation/testdata/entityresolver/entity.resolvers.go @@ -2,7 +2,7 @@ package entityresolver // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.21-dev DO NOT EDIT. +// Code generated by github.com/99designs/gqlgen version v0.17.21-dev import ( "context" diff --git a/plugin/resolvergen/resolver.go b/plugin/resolvergen/resolver.go index 3f136ab03f..189a79fdcb 100644 --- a/plugin/resolvergen/resolver.go +++ b/plugin/resolvergen/resolver.go @@ -155,7 +155,7 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error { FileNotice: ` // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. - // Code generated by github.com/99designs/gqlgen version ` + graphql.Version + ` DO NOT EDIT.`, + // Code generated by github.com/99designs/gqlgen version ` + graphql.Version, Filename: filename, Data: resolverBuild, Packages: data.Config.Packages,