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