-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#814 Add Transport Layer: AWS Lambda #815
Changes from all commits
c02c86e
92a7ef3
4250690
0c20a3a
4d460b1
095df04
a81b28e
9561ebf
4b8444b
d05a7ed
6a3be3a
d29f5a3
4fd90b0
50e8961
356f722
bceaf55
fe44f2d
4c4334a
9e2d959
cad1fdc
3de95b5
62efc64
19d5afe
6a69716
5a7cbf4
e831b16
1be9848
4f01057
a04bdd6
40f8b1a
1a31338
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package awslambda provides an AWS Lambda transport layer. | ||
package awslambda |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package awslambda | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
// DecodeRequestFunc extracts a user-domain request object from an | ||
// AWS Lambda payload. | ||
type DecodeRequestFunc func(context.Context, []byte) (interface{}, error) | ||
|
||
// EncodeResponseFunc encodes the passed response object into []byte, | ||
// ready to be sent as AWS Lambda response. | ||
type EncodeResponseFunc func(context.Context, interface{}) ([]byte, error) | ||
|
||
// ErrorEncoder is responsible for encoding an error. | ||
type ErrorEncoder func(ctx context.Context, err error) ([]byte, error) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package awslambda | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-kit/kit/endpoint" | ||
"github.com/go-kit/kit/log" | ||
) | ||
|
||
// Handler wraps an endpoint. | ||
type Handler struct { | ||
e endpoint.Endpoint | ||
dec DecodeRequestFunc | ||
enc EncodeResponseFunc | ||
before []HandlerRequestFunc | ||
after []HandlerResponseFunc | ||
errorEncoder ErrorEncoder | ||
finalizer []HandlerFinalizerFunc | ||
logger log.Logger | ||
} | ||
|
||
// NewHandler constructs a new handler, which implements | ||
// the AWS lambda.Handler interface. | ||
func NewHandler( | ||
e endpoint.Endpoint, | ||
dec DecodeRequestFunc, | ||
enc EncodeResponseFunc, | ||
options ...HandlerOption, | ||
) *Handler { | ||
h := &Handler{ | ||
e: e, | ||
dec: dec, | ||
enc: enc, | ||
logger: log.NewNopLogger(), | ||
errorEncoder: DefaultErrorEncoder, | ||
} | ||
for _, option := range options { | ||
option(h) | ||
} | ||
return h | ||
} | ||
|
||
// HandlerOption sets an optional parameter for handlers. | ||
type HandlerOption func(*Handler) | ||
|
||
// HandlerBefore functions are executed on the payload byte, | ||
// before the request is decoded. | ||
func HandlerBefore(before ...HandlerRequestFunc) HandlerOption { | ||
return func(h *Handler) { h.before = append(h.before, before...) } | ||
} | ||
|
||
// HandlerAfter functions are only executed after invoking the endpoint | ||
// but prior to returning a response. | ||
func HandlerAfter(after ...HandlerResponseFunc) HandlerOption { | ||
return func(h *Handler) { h.after = append(h.after, after...) } | ||
} | ||
|
||
// HandlerErrorLogger is used to log non-terminal errors. | ||
// By default, no errors are logged. | ||
func HandlerErrorLogger(logger log.Logger) HandlerOption { | ||
return func(h *Handler) { h.logger = logger } | ||
} | ||
|
||
// HandlerErrorEncoder is used to encode errors. | ||
func HandlerErrorEncoder(ee ErrorEncoder) HandlerOption { | ||
return func(h *Handler) { h.errorEncoder = ee } | ||
} | ||
|
||
// HandlerFinalizer sets finalizer which are called at the end of | ||
// request. By default no finalizer is registered. | ||
func HandlerFinalizer(f ...HandlerFinalizerFunc) HandlerOption { | ||
return func(h *Handler) { h.finalizer = append(h.finalizer, f...) } | ||
} | ||
|
||
// DefaultErrorEncoder defines the default behavior of encoding an error response, | ||
// where it returns nil, and the error itself. | ||
func DefaultErrorEncoder(ctx context.Context, err error) ([]byte, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this code is now uncovered by the tests? Though I obviously don't expect it to have bugs 😉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add it in 1a31338 |
||
return nil, err | ||
} | ||
|
||
// Invoke represents implementation of the AWS lambda.Handler interface. | ||
func (h *Handler) Invoke( | ||
ctx context.Context, | ||
payload []byte, | ||
) (resp []byte, err error) { | ||
if len(h.finalizer) > 0 { | ||
defer func() { | ||
for _, f := range h.finalizer { | ||
f(ctx, resp, err) | ||
} | ||
}() | ||
} | ||
|
||
for _, f := range h.before { | ||
ctx = f(ctx, payload) | ||
} | ||
|
||
request, err := h.dec(ctx, payload) | ||
if err != nil { | ||
h.logger.Log("err", err) | ||
return h.errorEncoder(ctx, err) | ||
} | ||
|
||
response, err := h.e(ctx, request) | ||
if err != nil { | ||
h.logger.Log("err", err) | ||
return h.errorEncoder(ctx, err) | ||
} | ||
|
||
for _, f := range h.after { | ||
ctx = f(ctx, response) | ||
} | ||
|
||
if resp, err = h.enc(ctx, response); err != nil { | ||
h.logger.Log("err", err) | ||
return h.errorEncoder(ctx, err) | ||
} | ||
|
||
return resp, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To what? Is the []byte returned just like a response?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are u referring to
ErrorEncoder
? if it is - then yes, the []byte is for controlling the response, for example in the context of building an API, we might want to response gracefully with a body of JSON describing detail of the error to Consumer.