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