1
0

handler.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  2. package lambda
  3. import (
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "reflect"
  8. )
  9. type Handler interface {
  10. Invoke(ctx context.Context, payload []byte) ([]byte, error)
  11. }
  12. // lambdaHandler is the generic function type
  13. type lambdaHandler func(context.Context, []byte) (interface{}, error)
  14. // Invoke calls the handler, and serializes the response.
  15. // If the underlying handler returned an error, or an error occurs during serialization, error is returned.
  16. func (handler lambdaHandler) Invoke(ctx context.Context, payload []byte) ([]byte, error) {
  17. response, err := handler(ctx, payload)
  18. if err != nil {
  19. return nil, err
  20. }
  21. responseBytes, err := json.Marshal(response)
  22. if err != nil {
  23. return nil, err
  24. }
  25. return responseBytes, nil
  26. }
  27. func errorHandler(e error) lambdaHandler {
  28. return func(ctx context.Context, event []byte) (interface{}, error) {
  29. return nil, e
  30. }
  31. }
  32. func validateArguments(handler reflect.Type) (bool, error) {
  33. handlerTakesContext := false
  34. if handler.NumIn() > 2 {
  35. return false, fmt.Errorf("handlers may not take more than two arguments, but handler takes %d", handler.NumIn())
  36. } else if handler.NumIn() > 0 {
  37. contextType := reflect.TypeOf((*context.Context)(nil)).Elem()
  38. argumentType := handler.In(0)
  39. handlerTakesContext = argumentType.Implements(contextType)
  40. if handler.NumIn() > 1 && !handlerTakesContext {
  41. return false, fmt.Errorf("handler takes two arguments, but the first is not Context. got %s", argumentType.Kind())
  42. }
  43. }
  44. return handlerTakesContext, nil
  45. }
  46. func validateReturns(handler reflect.Type) error {
  47. errorType := reflect.TypeOf((*error)(nil)).Elem()
  48. if handler.NumOut() > 2 {
  49. return fmt.Errorf("handler may not return more than two values")
  50. } else if handler.NumOut() > 1 {
  51. if !handler.Out(1).Implements(errorType) {
  52. return fmt.Errorf("handler returns two values, but the second does not implement error")
  53. }
  54. } else if handler.NumOut() == 1 {
  55. if !handler.Out(0).Implements(errorType) {
  56. return fmt.Errorf("handler returns a single value, but it does not implement error")
  57. }
  58. }
  59. return nil
  60. }
  61. // NewHandler creates a base lambda handler from the given handler function. The
  62. // returned Handler performs JSON deserialization and deserialization, and
  63. // delegates to the input handler function. The handler function parameter must
  64. // satisfy the rules documented by Start. If handlerFunc is not a valid
  65. // handler, the returned Handler simply reports the validation error.
  66. func NewHandler(handlerFunc interface{}) Handler {
  67. if handlerFunc == nil {
  68. return errorHandler(fmt.Errorf("handler is nil"))
  69. }
  70. handler := reflect.ValueOf(handlerFunc)
  71. handlerType := reflect.TypeOf(handlerFunc)
  72. if handlerType.Kind() != reflect.Func {
  73. return errorHandler(fmt.Errorf("handler kind %s is not %s", handlerType.Kind(), reflect.Func))
  74. }
  75. takesContext, err := validateArguments(handlerType)
  76. if err != nil {
  77. return errorHandler(err)
  78. }
  79. if err := validateReturns(handlerType); err != nil {
  80. return errorHandler(err)
  81. }
  82. return lambdaHandler(func(ctx context.Context, payload []byte) (interface{}, error) {
  83. // construct arguments
  84. var args []reflect.Value
  85. if takesContext {
  86. args = append(args, reflect.ValueOf(ctx))
  87. }
  88. if (handlerType.NumIn() == 1 && !takesContext) || handlerType.NumIn() == 2 {
  89. eventType := handlerType.In(handlerType.NumIn() - 1)
  90. event := reflect.New(eventType)
  91. if err := json.Unmarshal(payload, event.Interface()); err != nil {
  92. return nil, err
  93. }
  94. args = append(args, event.Elem())
  95. }
  96. response := handler.Call(args)
  97. // convert return values into (interface{}, error)
  98. var err error
  99. if len(response) > 0 {
  100. if errVal, ok := response[len(response)-1].Interface().(error); ok {
  101. err = errVal
  102. }
  103. }
  104. var val interface{}
  105. if len(response) > 1 {
  106. val = response[0].Interface()
  107. }
  108. return val, err
  109. })
  110. }