github.com/mstephano/gqlgen-schemagen@v0.0.0-20230113041936-dd2cd4ea46aa/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/mstephano/gqlgen-schemagen/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  
    52  ```json
    53  {
    54  	"data": {
    55  		"todo": null
    56  	},
    57  	"errors": [
    58  		{ "message": "Error 1", "path": ["todo"] },
    59  		{ "message": "zzzzzt", "path": ["todo"] },
    60  		{
    61  			"message": "A descriptive error message",
    62  			"path": ["todo"],
    63  			"extensions": { "code": "10-4" }
    64  		},
    65  		{ "message": "BOOM! Headshot", "path": ["todo"] }
    66  	]
    67  }
    68  ```
    69  
    70  or you can simply return multiple errors
    71  
    72  ```go
    73  package foo
    74  
    75  import (
    76  	"context"
    77  	"errors"
    78  
    79  	"github.com/vektah/gqlparser/v2/gqlerror"
    80  	"github.com/mstephano/gqlgen-schemagen/graphql"
    81  )
    82  
    83  var errSomethingWrong = errors.New("some validation failed")
    84  
    85  // DoThingsReturnMultipleErrors collect errors and returns it if any.
    86  func (r Query) DoThingsReturnMultipleErrors(ctx context.Context) (bool, error) {
    87  	errList := gqlerror.List{}
    88  
    89  	// Add existing error
    90  	errList = append(errList, gqlerror.Wrap(errSomethingWrong))
    91  
    92  	// Create new formatted and append
    93  	errList = append(errList, gqlerror.Errorf("invalid value: %s", "invalid"))
    94  
    95  	// Or fully customize the error and append
    96  	errList = append(errList, &gqlerror.Error{
    97  		Path:       graphql.GetPath(ctx),
    98  		Message:    "A descriptive error message",
    99  		Extensions: map[string]interface{}{
   100  			"code": "10-4",
   101  		},
   102  	})
   103  
   104  	return false, errList
   105  }
   106  ```
   107  
   108  They will be returned in the same order in the response, eg:
   109  
   110  ```json
   111  {
   112  	"data": {
   113  		"todo": null
   114  	},
   115  	"errors": [
   116  		{ "message": "some validation failed", "path": ["todo"] },
   117  		{ "message": "invalid value: invalid", "path": ["todo"] },
   118  		{ "message": "A descriptive error message", "path": ["todo"], "extensions": { "code": "10-4" } }
   119  	]
   120  }
   121  ```
   122  
   123  ## Hooks
   124  
   125  ### The error presenter
   126  
   127  All `errors` returned by resolvers, or from validation, pass through a hook before being displayed to the user.
   128  This hook gives you the ability to customise errors however makes sense in your app.
   129  
   130  The default error presenter will capture the resolver path and use the Error() message in the response.
   131  
   132  You change this when creating the server:
   133  
   134  ```go
   135  package bar
   136  
   137  import (
   138  	"context"
   139  	"errors"
   140  
   141  	"github.com/vektah/gqlparser/v2/gqlerror"
   142  	"github.com/mstephano/gqlgen-schemagen/graphql"
   143  	"github.com/mstephano/gqlgen-schemagen/graphql/handler"
   144  )
   145  
   146  func main() {
   147  	server := handler.NewDefaultServer(MakeExecutableSchema(resolvers))
   148  	server.SetErrorPresenter(func(ctx context.Context, e error) *gqlerror.Error {
   149  		err := graphql.DefaultErrorPresenter(ctx, e)
   150  
   151  		var myErr *MyError
   152  		if errors.As(e, &myErr) {
   153  			err.Message = "Eeek!"
   154  		}
   155  
   156  		return err
   157  	})
   158  }
   159  
   160  ```
   161  
   162  This function will be called with the same resolver context that generated it, so you can extract the
   163  current resolver path and whatever other state you might want to notify the client about.
   164  
   165  ### The panic handler
   166  
   167  There is also a panic handler, called whenever a panic happens to gracefully return a message to the user before
   168  stopping parsing. This is a good spot to notify your bug tracker and send a custom message to the user. Any errors
   169  returned from here will also go through the error presenter.
   170  
   171  You change this when creating the server:
   172  
   173  ```go
   174  server := handler.NewDefaultServer(MakeExecutableSchema(resolvers)
   175  server.SetRecoverFunc(func(ctx context.Context, err interface{}) error {
   176      // notify bug tracker...
   177  
   178  		return gqlerror.Errorf("Internal server error!")
   179  })
   180  ```