Skip to content

Commit 12f536e

Browse files
authored
Merge pull request #58 from graphql-go/formatErrorFn
handler: adds formatErrorFn
2 parents 28550b4 + 202b989 commit 12f536e

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ _testmain.go
2323
*.test
2424
*.prof
2525
*.swp
26+
.idea

handler.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"github.com/graphql-go/graphql"
1111

1212
"context"
13+
14+
"github.com/graphql-go/graphql/gqlerrors"
1315
)
1416

1517
const (
@@ -27,7 +29,9 @@ type Handler struct {
2729
playground bool
2830
rootObjectFn RootObjectFn
2931
resultCallbackFn ResultCallbackFn
32+
formatErrorFn func(err gqlerrors.FormattedError) gqlerrors.FormattedError
3033
}
34+
3135
type RequestOptions struct {
3236
Query string `json:"query" url:"query" schema:"query"`
3337
Variables map[string]interface{} `json:"variables" url:"variables" schema:"variables"`
@@ -137,6 +141,14 @@ func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *
137141
}
138142
result := graphql.Do(params)
139143

144+
if formatErrorFn := h.formatErrorFn; formatErrorFn != nil && len(result.Errors) > 0 {
145+
formatted := make([]gqlerrors.FormattedError, len(result.Errors))
146+
for i, formattedError := range result.Errors {
147+
formatted[i] = formatErrorFn(formattedError)
148+
}
149+
result.Errors = formatted
150+
}
151+
140152
if h.graphiql {
141153
acceptHeader := r.Header.Get("Accept")
142154
_, raw := r.URL.Query()["raw"]
@@ -191,6 +203,7 @@ type Config struct {
191203
Playground bool
192204
RootObjectFn RootObjectFn
193205
ResultCallbackFn ResultCallbackFn
206+
FormatErrorFn func(err gqlerrors.FormattedError) gqlerrors.FormattedError
194207
}
195208

196209
func NewConfig() *Config {
@@ -206,6 +219,7 @@ func New(p *Config) *Handler {
206219
if p == nil {
207220
p = NewConfig()
208221
}
222+
209223
if p.Schema == nil {
210224
panic("undefined GraphQL schema")
211225
}
@@ -217,5 +231,6 @@ func New(p *Config) *Handler {
217231
playground: p.Playground,
218232
rootObjectFn: p.RootObjectFn,
219233
resultCallbackFn: p.ResultCallbackFn,
234+
formatErrorFn: p.FormatErrorFn,
220235
}
221236
}

handler_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package handler_test
22

33
import (
44
"encoding/json"
5+
"errors"
56
"fmt"
67
"io/ioutil"
78
"net/http"
@@ -13,6 +14,8 @@ import (
1314
"context"
1415

1516
"github.com/graphql-go/graphql"
17+
"github.com/graphql-go/graphql/gqlerrors"
18+
"github.com/graphql-go/graphql/language/location"
1619
"github.com/graphql-go/graphql/testutil"
1720
"github.com/graphql-go/handler"
1821
)
@@ -210,3 +213,90 @@ func TestHandler_BasicQuery_WithRootObjFn(t *testing.T) {
210213
t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result))
211214
}
212215
}
216+
217+
type customError struct {
218+
error
219+
}
220+
221+
func (e customError) Error() string {
222+
return e.error.Error()
223+
}
224+
225+
func TestHandler_BasicQuery_WithFormatErrorFn(t *testing.T) {
226+
resolverError := customError{error: errors.New("resolver error")}
227+
myNameQuery := graphql.NewObject(graphql.ObjectConfig{
228+
Name: "Query",
229+
Fields: graphql.Fields{
230+
"name": &graphql.Field{
231+
Name: "name",
232+
Type: graphql.String,
233+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
234+
return nil, resolverError
235+
},
236+
},
237+
},
238+
})
239+
myNameSchema, err := graphql.NewSchema(graphql.SchemaConfig{
240+
Query: myNameQuery,
241+
})
242+
if err != nil {
243+
t.Fatal(err)
244+
}
245+
246+
customFormattedError := gqlerrors.FormattedError{
247+
Message: resolverError.Error(),
248+
Locations: []location.SourceLocation{
249+
location.SourceLocation{
250+
Line: 1,
251+
Column: 2,
252+
},
253+
},
254+
Path: []interface{}{"name"},
255+
Extensions: map[string]interface{}{
256+
"fromFormatFn": "FROM_FORMAT_FN",
257+
},
258+
}
259+
260+
expected := &graphql.Result{
261+
Data: map[string]interface{}{
262+
"name": nil,
263+
},
264+
Errors: []gqlerrors.FormattedError{customFormattedError},
265+
}
266+
267+
queryString := `query={name}`
268+
req, _ := http.NewRequest("GET", fmt.Sprintf("/graphql?%v", queryString), nil)
269+
270+
formatErrorFnCalled := false
271+
h := handler.New(&handler.Config{
272+
Schema: &myNameSchema,
273+
Pretty: true,
274+
FormatErrorFn: func(err gqlerrors.FormattedError) gqlerrors.FormattedError {
275+
formatErrorFnCalled = true
276+
originalError := err.OriginalError()
277+
switch errType := originalError.(type) {
278+
case customError:
279+
default:
280+
t.Fatalf("unexpected error type: %v", reflect.TypeOf(errType))
281+
}
282+
return gqlerrors.FormattedError{
283+
Message: err.Message,
284+
Locations: err.Locations,
285+
Path: err.Path,
286+
Extensions: map[string]interface{}{
287+
"fromFormatFn": "FROM_FORMAT_FN",
288+
},
289+
}
290+
},
291+
})
292+
result, resp := executeTest(t, h, req)
293+
if resp.Code != http.StatusOK {
294+
t.Fatalf("unexpected server response %v", resp.Code)
295+
}
296+
if !formatErrorFnCalled {
297+
t.Fatalf("FormatErrorFn was not called when it should have been")
298+
}
299+
if !reflect.DeepEqual(result, expected) {
300+
t.Fatalf("wrong result, graphql result diff: %v", testutil.Diff(expected, result))
301+
}
302+
}

0 commit comments

Comments
 (0)