-
Notifications
You must be signed in to change notification settings - Fork 0
/
rack.go
143 lines (119 loc) · 2.9 KB
/
rack.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package rack
import (
"context"
"net/http"
"net/url"
"sync"
"github.com/aws/aws-lambda-go/lambda"
)
type (
// HandlerFunc represents a handler function
HandlerFunc func(Context) error
// MiddlewareFunc represents a middleware function
MiddlewareFunc func(HandlerFunc) HandlerFunc
// Config represent handler configuration
Config struct {
Resolver Resolver
Middleware MiddlewareFunc
OnBind func(Context, interface{}) error
OnError func(Context, error) error
OnEmptyResponse HandlerFunc
}
// Request represents a canonical request type
Request struct {
Method string
RawPath string
Path map[string]string
Query url.Values
Header http.Header
Body string
Event interface{}
}
// Response represents a canonical response type
Response struct {
StatusCode int
Headers http.Header
Body string
}
invokeFunc func(context.Context, []byte) ([]byte, error)
)
// New returns a new lambda handler for the specified function
func New(h HandlerFunc) lambda.Handler {
return NewWithConfig(Config{}, h)
}
// NewWithConfig returns a new lambda handler for the specified function and configuration
func NewWithConfig(c Config, h HandlerFunc) lambda.Handler {
if c.Middleware != nil {
h = c.Middleware(h)
}
resolver := c.Resolver
if resolver == nil {
resolver = defaultResolver
}
onError := c.OnError
if onError == nil {
onError = defaultErrorHandler
}
onBind := c.OnBind
if onBind == nil {
onBind = func(Context, interface{}) error { return nil }
}
onEmptyResponse := c.OnEmptyResponse
if onEmptyResponse == nil {
onEmptyResponse = func(c Context) error {
return c.NoContent(http.StatusOK)
}
}
return invokeFunc(func(ctx context.Context, payload []byte) ([]byte, error) {
p, err := resolver.Resolve(payload)
if err != nil {
return nil, err
}
req, err := p.UnmarshalRequest(payload)
if err != nil {
return nil, err
}
c := &handlerContext{
ctx: ctx,
request: req,
response: &Response{
Headers: http.Header{},
},
onBind: onBind,
mu: new(sync.RWMutex),
}
if err = h(c); err != nil {
if err = onError(c, err); err != nil {
return nil, err
}
}
if c.response.StatusCode == 0 {
if err = onEmptyResponse(c); err != nil {
if err = onError(c, err); err != nil {
return nil, err
}
}
}
return p.MarshalResponse(c.response)
})
}
// Chain returns a middleware func that chains the specified funcs
func Chain(m ...MiddlewareFunc) MiddlewareFunc {
return MiddlewareFunc(func(n HandlerFunc) HandlerFunc {
for i := len(m) - 1; i >= 0; i-- {
n = m[i](n)
}
return n
})
}
func (fn invokeFunc) Invoke(ctx context.Context, payload []byte) ([]byte, error) {
return fn(ctx, payload)
}
func defaultErrorHandler(c Context, err error) error {
res := struct {
Message string `json:"message"`
}{
Message: err.Error(),
}
return c.JSON(StatusCode(err), &res)
}