github.com/dgraph-io/dgraph@v1.2.8/graphql/schema/errors.go (about) 1 /* 2 * Copyright 2019 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package schema 18 19 import ( 20 "fmt" 21 22 "github.com/dgraph-io/dgraph/x" 23 "github.com/vektah/gqlparser/gqlerror" 24 ) 25 26 // AsGQLErrors formats an error as a list of GraphQL errors. 27 // A []*x.GqlError (x.GqlErrorList) gets returned as is, an x.GqlError gets returned as a one 28 // item list, and all other errors get printed into a x.GqlError . A nil input results 29 // in nil output. 30 func AsGQLErrors(err error) x.GqlErrorList { 31 if err == nil { 32 return nil 33 } 34 35 switch e := err.(type) { 36 case *gqlerror.Error: 37 return x.GqlErrorList{toGqlError(e)} 38 case *x.GqlError: 39 return x.GqlErrorList{e} 40 case gqlerror.List: 41 return toGqlErrorList(e) 42 case x.GqlErrorList: 43 return e 44 default: 45 return x.GqlErrorList{&x.GqlError{Message: e.Error()}} 46 } 47 } 48 49 func toGqlError(err *gqlerror.Error) *x.GqlError { 50 return &x.GqlError{ 51 Message: err.Message, 52 Locations: convertLocations(err.Locations), 53 Path: err.Path, 54 } 55 } 56 57 func toGqlErrorList(errs gqlerror.List) x.GqlErrorList { 58 var result x.GqlErrorList 59 for _, err := range errs { 60 result = append(result, toGqlError(err)) 61 } 62 return result 63 } 64 65 func convertLocations(locs []gqlerror.Location) []x.Location { 66 var result []x.Location 67 for _, loc := range locs { 68 result = append(result, x.Location{Line: loc.Line, Column: loc.Column}) 69 } 70 return result 71 } 72 73 // GQLWrapf takes an existing error and wraps it as a GraphQL error. 74 // If err is already a GraphQL error, any location information is kept in the 75 // new error. If err is nil, GQLWrapf returns nil. 76 // 77 // Wrapping GraphQL errors like this allows us to bubble errors up the stack 78 // and add context, location and path info to them as we go. 79 func GQLWrapf(err error, format string, args ...interface{}) error { 80 if err == nil { 81 return nil 82 } 83 84 switch err := err.(type) { 85 case *x.GqlError: 86 return x.GqlErrorf("%s because %s", fmt.Sprintf(format, args...), err.Message). 87 WithLocations(err.Locations...). 88 WithPath(err.Path) 89 case x.GqlErrorList: 90 var errs x.GqlErrorList 91 for _, e := range err { 92 errs = append(errs, GQLWrapf(e, format, args...).(*x.GqlError)) 93 } 94 return errs 95 default: 96 return x.GqlErrorf("%s because %s", fmt.Sprintf(format, args...), err.Error()) 97 } 98 } 99 100 // GQLWrapLocationf wraps an error as a GraphQL error and includes location 101 // information in the GraphQL error. 102 func GQLWrapLocationf(err error, loc x.Location, format string, args ...interface{}) error { 103 wrapped := GQLWrapf(err, format, args...) 104 if wrapped == nil { 105 return nil 106 } 107 108 switch wrapped := wrapped.(type) { 109 case *x.GqlError: 110 return wrapped.WithLocations(loc) 111 case x.GqlErrorList: 112 for _, e := range wrapped { 113 _ = e.WithLocations(loc) 114 } 115 } 116 return wrapped 117 } 118 119 // AppendGQLErrs builds a list of GraphQL errors from err1 and err2, if both 120 // are nil, the result is nil. 121 func AppendGQLErrs(err1, err2 error) error { 122 if err1 == nil && err2 == nil { 123 return nil 124 } 125 if err1 == nil { 126 return AsGQLErrors(err2) 127 } 128 if err2 == nil { 129 return AsGQLErrors(err1) 130 } 131 return append(AsGQLErrors(err1), AsGQLErrors(err2)...) 132 }