github.com/99designs/gqlgen@v0.17.45/docs/content/reference/errors.md (about) 1 --- 2 linkTitle: Handling Errors 3 title: Sending custom error data in the graphql response 4 description: Customising graphql error types to send custom error data back to the client using gqlgen. 5 menu: { main: { parent: 'reference', weight: 10 } } 6 --- 7 8 ## Returning errors 9 10 All resolvers simply return an error to be sent to the user. The assumption is that any error message returned 11 here is appropriate for end users. If certain messages aren't safe, customise the error presenter. 12 13 ### Multiple errors 14 15 To return multiple errors you can call the `graphql.Error` functions like so: 16 17 ```go 18 package foo 19 20 import ( 21 "context" 22 "errors" 23 24 "github.com/vektah/gqlparser/v2/gqlerror" 25 "github.com/99designs/gqlgen/graphql" 26 ) 27 28 // DoThings add errors to the stack. 29 func (r Query) DoThings(ctx context.Context) (bool, error) { 30 // Print a formatted string 31 graphql.AddErrorf(ctx, "Error %d", 1) 32 33 // Pass an existing error out 34 graphql.AddError(ctx, gqlerror.Errorf("zzzzzt")) 35 36 // Or fully customize the error 37 graphql.AddError(ctx, &gqlerror.Error{ 38 Path: graphql.GetPath(ctx), 39 Message: "A descriptive error message", 40 Extensions: map[string]interface{}{ 41 "code": "10-4", 42 }, 43 }) 44 45 // And you can still return an error if you need 46 return false, gqlerror.Errorf("BOOM! Headshot") 47 } 48 ``` 49 50 They will be returned in the same order in the response, eg: 51 ```json 52 { 53 "data": { 54 "todo": null 55 }, 56 "errors": [ 57 { "message": "Error 1", "path": [ "todo" ] }, 58 { "message": "zzzzzt", "path": [ "todo" ] }, 59 { "message": "A descriptive error message", "path": [ "todo" ], "extensions": { "code": "10-4" } }, 60 { "message": "BOOM! Headshot", "path": [ "todo" ] } 61 ] 62 } 63 ``` 64 65 or you can simply return multiple errors 66 67 ```go 68 package foo 69 70 import ( 71 "context" 72 "errors" 73 74 "github.com/vektah/gqlparser/v2/gqlerror" 75 "github.com/99designs/gqlgen/graphql" 76 ) 77 78 var errSomethingWrong = errors.New("some validation failed") 79 80 // DoThingsReturnMultipleErrors collect errors and returns it if any. 81 func (r Query) DoThingsReturnMultipleErrors(ctx context.Context) (bool, error) { 82 errList := gqlerror.List{} 83 84 // Add existing error 85 errList = append(errList, gqlerror.Wrap(errSomethingWrong)) 86 87 // Create new formatted and append 88 errList = append(errList, gqlerror.Errorf("invalid value: %s", "invalid")) 89 90 // Or fully customize the error and append 91 errList = append(errList, &gqlerror.Error{ 92 Path: graphql.GetPath(ctx), 93 Message: "A descriptive error message", 94 Extensions: map[string]interface{}{ 95 "code": "10-4", 96 }, 97 }) 98 99 return false, errList 100 } 101 ``` 102 103 They will be returned in the same order in the response, eg: 104 ```json 105 { 106 "data": { 107 "todo": null 108 }, 109 "errors": [ 110 { "message": "some validation failed", "path": [ "todo" ] }, 111 { "message": "invalid value: invalid", "path": [ "todo" ] }, 112 { "message": "A descriptive error message", "path": [ "todo" ], "extensions": { "code": "10-4" } }, 113 ] 114 } 115 ``` 116 117 ## Hooks 118 119 ### The error presenter 120 121 All `errors` returned by resolvers, or from validation, pass through a hook before being displayed to the user. 122 This hook gives you the ability to customise errors however makes sense in your app. 123 124 The default error presenter will capture the resolver path and use the Error() message in the response. 125 126 You change this when creating the server: 127 ```go 128 package bar 129 130 import ( 131 "context" 132 "errors" 133 134 "github.com/vektah/gqlparser/v2/gqlerror" 135 "github.com/99designs/gqlgen/graphql" 136 "github.com/99designs/gqlgen/graphql/handler" 137 ) 138 139 func main() { 140 server := handler.NewDefaultServer(MakeExecutableSchema(resolvers)) 141 server.SetErrorPresenter(func(ctx context.Context, e error) *gqlerror.Error { 142 err := graphql.DefaultErrorPresenter(ctx, e) 143 144 var myErr *MyError 145 if errors.As(e, &myErr) { 146 err.Message = "Eeek!" 147 } 148 149 return err 150 }) 151 } 152 153 ``` 154 155 This function will be called with the same resolver context that generated it, so you can extract the 156 current resolver path and whatever other state you might want to notify the client about. 157 158 159 ### The panic handler 160 161 There is also a panic handler, called whenever a panic happens to gracefully return a message to the user before 162 stopping parsing. This is a good spot to notify your bug tracker and send a custom message to the user. Any errors 163 returned from here will also go through the error presenter. 164 165 You change this when creating the server: 166 ```go 167 server := handler.NewDefaultServer(MakeExecutableSchema(resolvers)) 168 server.SetRecoverFunc(func(ctx context.Context, err interface{}) error { 169 // notify bug tracker... 170 171 return gqlerror.Errorf("Internal server error!") 172 }) 173 ``` 174