diff --git a/dynamic/errors.go b/dynamic/errors.go index 60acaec..e3d7546 100644 --- a/dynamic/errors.go +++ b/dynamic/errors.go @@ -14,11 +14,8 @@ const ErrHandlerNotFunc = cerr("handler must be a func") // ErrNoServiceForHandler - no service matching this handler const ErrNoServiceForHandler = cerr("no service found for this handler") -// ErrMissingHandlerArgument - missing arguments for handler -const ErrMissingHandlerArgument = cerr("handler must have at least 1 arguments") - // ErrMissingHandlerArgumentParam - missing params arguments for handler -const ErrMissingHandlerArgumentParam = cerr("missing handler argument 2 : parameter struct") +const ErrMissingHandlerArgumentParam = cerr("missing handler argument : parameter struct") // ErrMissingHandlerOutput - missing output for handler const ErrMissingHandlerOutput = cerr("handler must have at least 1 output") @@ -33,7 +30,7 @@ const ErrMissingRequestArgument = cerr("handler first argument must be of type a const ErrMissingParamArgument = cerr("handler second argument must be a struct") // ErrMissingParamOutput - missing output argument for handler -const ErrMissingParamOutput = cerr("handler first output must be a struct") +const ErrMissingParamOutput = cerr("handler first output must be a *struct") // ErrMissingParamFromConfig - missing a parameter in handler struct const ErrMissingParamFromConfig = cerr("missing a parameter from configuration") @@ -42,10 +39,10 @@ const ErrMissingParamFromConfig = cerr("missing a parameter from configuration") const ErrMissingOutputFromConfig = cerr("missing a parameter from configuration") // ErrWrongParamTypeFromConfig - a configuration parameter type is invalid in the handler param struct -const ErrWrongParamTypeFromConfig = cerr("invalid parameter struct type from configuration") +const ErrWrongParamTypeFromConfig = cerr("invalid struct field type") // ErrWrongOutputTypeFromConfig - a configuration output type is invalid in the handler output struct -const ErrWrongOutputTypeFromConfig = cerr("invalid output struct type from configuration") +const ErrWrongOutputTypeFromConfig = cerr("invalid struct field type") // ErrMissingHandlerErrorOutput - missing handler output error const ErrMissingHandlerErrorOutput = cerr("last output must be of type api.Error") diff --git a/dynamic/handler.go b/dynamic/handler.go index 2be0957..b2b8a3b 100644 --- a/dynamic/handler.go +++ b/dynamic/handler.go @@ -22,16 +22,16 @@ func Build(fn HandlerFn, service config.Service) (*Handler, error) { fn: fn, } - fnt := reflect.TypeOf(fn) + fnv := reflect.ValueOf(fn) - if fnt.Kind() != reflect.Func { + if fnv.Type().Kind() != reflect.Func { return nil, ErrHandlerNotFunc } - if err := h.spec.checkInput(fnt); err != nil { + if err := h.spec.checkInput(fnv); err != nil { return nil, fmt.Errorf("input: %w", err) } - if err := h.spec.checkOutput(fnt); err != nil { + if err := h.spec.checkOutput(fnv); err != nil { return nil, fmt.Errorf("output: %w", err) } diff --git a/dynamic/spec.go b/dynamic/spec.go index e7e5016..354df52 100644 --- a/dynamic/spec.go +++ b/dynamic/spec.go @@ -25,11 +25,6 @@ func makeSpec(service config.Service) spec { } for _, param := range service.Output { - // make a pointer if optional - if param.Optional { - spec.Output[param.Rename] = reflect.PtrTo(param.ExtractType) - continue - } spec.Output[param.Rename] = param.ExtractType } @@ -37,28 +32,20 @@ func makeSpec(service config.Service) spec { } // checks for HandlerFn input arguments -func (s spec) checkInput(fnt reflect.Type) error { - if fnt.NumIn() != 1 { - return ErrMissingHandlerArgument - } - - // arg[0] must be api.Request - requestArg := fnt.In(0) - if !requestArg.AssignableTo(reflect.TypeOf(api.Request{})) { - return ErrMissingRequestArgument - } +func (s spec) checkInput(fnv reflect.Value) error { + fnt := fnv.Type() // no input -> ok if len(s.Input) == 0 { return nil } - if fnt.NumIn() < 2 { + if fnt.NumIn() != 1 { return ErrMissingHandlerArgumentParam } - // arg[1] must be a struct - structArg := fnt.In(1) + // arg must be a struct + structArg := fnt.In(0) if structArg.Kind() != reflect.Struct { return ErrMissingParamArgument } @@ -71,7 +58,7 @@ func (s spec) checkInput(fnt reflect.Type) error { } if !ptype.AssignableTo(field.Type) { - return fmt.Errorf("%s: %w (%s)", name, ErrWrongParamTypeFromConfig, ptype) + return fmt.Errorf("%s: %w (%s instead of %s)", name, ErrWrongParamTypeFromConfig, field.Type, ptype) } } @@ -79,7 +66,8 @@ func (s spec) checkInput(fnt reflect.Type) error { } // checks for HandlerFn output arguments -func (s spec) checkOutput(fnt reflect.Type) error { +func (s spec) checkOutput(fnv reflect.Value) error { + fnt := fnv.Type() if fnt.NumOut() < 1 { return ErrMissingHandlerOutput } @@ -99,10 +87,15 @@ func (s spec) checkOutput(fnt reflect.Type) error { return ErrMissingParamOutput } - // fail if first output is not a struct - structOutput := fnt.Out(0) + // fail if first output is not a pointer to struct + structOutputPtr := fnt.Out(0) + if structOutputPtr.Kind() != reflect.Ptr { + return ErrMissingParamOutput + } + + structOutput := structOutputPtr.Elem() if structOutput.Kind() != reflect.Struct { - return ErrMissingParamArgument + return ErrMissingParamOutput } // fail on invalid output @@ -112,8 +105,13 @@ func (s spec) checkOutput(fnt reflect.Type) error { return fmt.Errorf("%s: %w", name, ErrMissingOutputFromConfig) } - if !ptype.AssignableTo(field.Type) { - return fmt.Errorf("%s: %w (%s)", name, ErrWrongOutputTypeFromConfig, ptype) + // ignore types evalutating to nil + if ptype == nil { + continue + } + + if !ptype.ConvertibleTo(field.Type) { + return fmt.Errorf("%s: %w (%s instead of %s)", name, ErrWrongOutputTypeFromConfig, field.Type, ptype) } }