handler.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package hero
  2. import (
  3. "fmt"
  4. "reflect"
  5. "github.com/kataras/iris/context"
  6. )
  7. type (
  8. // ErrorHandler describes an interface to handle errors per hero handler and its dependencies.
  9. //
  10. // Handles non-nil errors return from a hero handler or a controller's method (see `getBindingsFor` and `Handler`)
  11. // the error may return from a request-scoped dependency too (see `Handler`).
  12. ErrorHandler interface {
  13. HandleError(*context.Context, error)
  14. }
  15. // ErrorHandlerFunc implements the `ErrorHandler`.
  16. // It describes the type defnition for an error function handler.
  17. ErrorHandlerFunc func(*context.Context, error)
  18. )
  19. // HandleError fires when a non-nil error returns from a request-scoped dependency at serve-time or the handler itself.
  20. func (fn ErrorHandlerFunc) HandleError(ctx *context.Context, err error) {
  21. fn(ctx, err)
  22. }
  23. var (
  24. // ErrSeeOther may be returned from a dependency handler to skip a specific dependency
  25. // based on custom logic.
  26. ErrSeeOther = fmt.Errorf("see other")
  27. // ErrStopExecution may be returned from a dependency handler to stop
  28. // and return the execution of the function without error (it calls ctx.StopExecution() too).
  29. // It may be occurred from request-scoped dependencies as well.
  30. ErrStopExecution = fmt.Errorf("stop execution")
  31. )
  32. var (
  33. // DefaultErrStatusCode is the default error status code (400)
  34. // when the response contains a non-nil error or a request-scoped binding error occur.
  35. DefaultErrStatusCode = 400
  36. // DefaultErrorHandler is the default error handler which is fired
  37. // when a function returns a non-nil error or a request-scoped dependency failed to binded.
  38. DefaultErrorHandler = ErrorHandlerFunc(func(ctx *context.Context, err error) {
  39. if err != ErrStopExecution {
  40. if status := ctx.GetStatusCode(); status == 0 || !context.StatusCodeNotSuccessful(status) {
  41. ctx.StatusCode(DefaultErrStatusCode)
  42. }
  43. _, _ = ctx.WriteString(err.Error())
  44. }
  45. ctx.StopExecution()
  46. })
  47. )
  48. func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler {
  49. if fn == nil {
  50. panic("makeHandler: function is nil")
  51. }
  52. // 0. A normal handler.
  53. if handler, ok := isHandler(fn); ok {
  54. return handler
  55. }
  56. // 1. A handler which returns just an error, handle it faster.
  57. if handlerWithErr, ok := isHandlerWithError(fn); ok {
  58. return func(ctx *context.Context) {
  59. if err := handlerWithErr(ctx); err != nil {
  60. c.GetErrorHandler(ctx).HandleError(ctx, err)
  61. }
  62. }
  63. }
  64. v := valueOf(fn)
  65. typ := v.Type()
  66. numIn := typ.NumIn()
  67. bindings := getBindingsForFunc(v, c.Dependencies, paramsCount)
  68. resultHandler := defaultResultHandler
  69. for i, lidx := 0, len(c.resultHandlers)-1; i <= lidx; i++ {
  70. resultHandler = c.resultHandlers[lidx-i](resultHandler)
  71. }
  72. return func(ctx *context.Context) {
  73. inputs := make([]reflect.Value, numIn)
  74. for _, binding := range bindings {
  75. input, err := binding.Dependency.Handle(ctx, binding.Input)
  76. if err != nil {
  77. if err == ErrSeeOther {
  78. continue
  79. }
  80. // handled inside ErrorHandler.
  81. // else if err == ErrStopExecution {
  82. // ctx.StopExecution()
  83. // return // return without error.
  84. // }
  85. c.GetErrorHandler(ctx).HandleError(ctx, err)
  86. return
  87. }
  88. // If ~an error status code is set or~ execution has stopped
  89. // from within the dependency (something went wrong while validating the request),
  90. // then stop everything and let handler fire that status code.
  91. if ctx.IsStopped() /* || context.StatusCodeNotSuccessful(ctx.GetStatusCode())*/ {
  92. return
  93. }
  94. inputs[binding.Input.Index] = input
  95. }
  96. // fmt.Printf("For func: %s | valid input deps length(%d)\n", typ.String(), len(inputs))
  97. // for idx, in := range inputs {
  98. // fmt.Printf("[%d] (%s) %#+v\n", idx, in.Type().String(), in.Interface())
  99. // }
  100. outputs := v.Call(inputs)
  101. if err := dispatchFuncResult(ctx, outputs, resultHandler); err != nil {
  102. c.GetErrorHandler(ctx).HandleError(ctx, err)
  103. }
  104. }
  105. }
  106. func isHandler(fn interface{}) (context.Handler, bool) {
  107. if handler, ok := fn.(context.Handler); ok {
  108. return handler, ok
  109. }
  110. if handler, ok := fn.(func(*context.Context)); ok {
  111. return handler, ok
  112. }
  113. return nil, false
  114. }
  115. func isHandlerWithError(fn interface{}) (func(*context.Context) error, bool) {
  116. if handlerWithErr, ok := fn.(func(*context.Context) error); ok {
  117. return handlerWithErr, true
  118. }
  119. return nil, false
  120. }