Skip to content

Instantly share code, notes, and snippets.

@koblas
Created September 29, 2019 15:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koblas/e4445009dc283ced30c34c6658b939c5 to your computer and use it in GitHub Desktop.
Save koblas/e4445009dc283ced30c34c6658b939c5 to your computer and use it in GitHub Desktop.
package resolver
import (
"reflect"
"strings"
"github.com/graphql-go/graphql"
"github.com/mitchellh/mapstructure"
"gopkg.in/asaskevich/govalidator.v4"
)
func flattenErrors(validationErrors []ValidationError, errs govalidator.Errors) []ValidationError {
for _, e := range errs {
if ge, ok := e.(govalidator.Error); ok {
validationErrors = append(validationErrors, ValidationError{
strings.ToLower(ge.Name),
ge.Err.Error(),
})
} else if ge, ok := e.(govalidator.Errors); ok {
validationErrors = flattenErrors(validationErrors, ge)
}
}
return validationErrors
}
func wrapGraphQL(wrap interface{}) func(p graphql.ResolveParams) (interface{}, error) {
return wrapLog(func(p graphql.ResolveParams) (interface{}, error) {
// Get the Value of the argument, so we can Call(...) it later
fValue := reflect.ValueOf(wrap)
// The type of the argument
fType := reflect.TypeOf(wrap)
// Basic checking that we're matching the expected arguments
if fType.Kind() != reflect.Func {
panic("Not a function")
}
// Expect a function that is
// (context.Context, struct{}, []*validationErrors) == 3 arguments
// OR (context.Context, struct{}, []*validationErrors, graphql.ResolveParams) == 3 arguments
if fType.NumIn() != 3 && fType.NumIn() != 4 {
panic("Wrong number of arguments")
}
// Construct the struct{} argument
arg := reflect.New(fType.In(1))
if err := mapstructure.Decode(p.Args, arg.Interface()); err != nil {
return nil, err
}
// Handle validation
var validationErrors []ValidationError
if result, err := govalidator.ValidateStruct(arg.Interface()); err != nil || !result {
if gerrs, ok := err.(govalidator.Errors); !ok {
// Unknown error from govalidator
return nil, err
} else {
validationErrors = flattenErrors(validationErrors, gerrs)
}
}
var result []reflect.Value
if fType.NumIn() == 3 {
// Call the wrapped function
result = fValue.Call([]reflect.Value{
reflect.ValueOf(p.Context),
reflect.Indirect(arg),
reflect.ValueOf(validationErrors),
})
} else {
result = fValue.Call([]reflect.Value{
reflect.ValueOf(p.Context),
reflect.Indirect(arg),
reflect.ValueOf(validationErrors),
reflect.ValueOf(p),
})
}
// See if we've got errors otherwise return nil
eResult := result[1].Interface()
if eResult != nil {
return result[0].Interface(), eResult.(error)
}
return result[0].Interface(), nil
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment