Skip to content
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

Merged
merged 31 commits into from
Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c02c86e
base serving, encode, decode functions
suekto-andreas Dec 22, 2018
92a7ef3
logger
suekto-andreas Dec 22, 2018
4250690
add before encode options
suekto-andreas Dec 22, 2018
0c20a3a
add ServerAfter functions
suekto-andreas Dec 22, 2018
4d460b1
add error encoder
suekto-andreas Dec 22, 2018
095df04
add finalizer
suekto-andreas Dec 22, 2018
a81b28e
add basic happy flow
suekto-andreas Dec 23, 2018
9561ebf
add ServerBefore tests
suekto-andreas Dec 23, 2018
4b8444b
test error flow on decoding stage
suekto-andreas Dec 23, 2018
d05a7ed
complete the test scenarios
suekto-andreas Dec 23, 2018
6a3be3a
refactor into more generic support by implementing lambda.Handler
suekto-andreas Dec 24, 2018
d29f5a3
testing: ErrorEncoder to reflect behavior of encoding error as payloa…
suekto-andreas Dec 26, 2018
4fd90b0
add wrapper
suekto-andreas Dec 26, 2018
50e8961
capitalize Lambda
suekto-andreas Jan 20, 2019
356f722
add particle an
suekto-andreas Jan 20, 2019
bceaf55
tidy up doc words as per suggested
suekto-andreas Jan 20, 2019
fe44f2d
Update transport/awslambda/request_response_funcs.go
peterbourgon Jan 20, 2019
4c4334a
Update transport/awslambda/request_response_funcs.go
peterbourgon Jan 20, 2019
9e2d959
Update transport/awslambda/server.go
peterbourgon Jan 20, 2019
cad1fdc
Update transport/awslambda/request_response_funcs.go
peterbourgon Jan 20, 2019
3de95b5
refactor multiline to keep them 1 per line
suekto-andreas Jan 20, 2019
62efc64
remove \n from test
suekto-andreas Jan 20, 2019
19d5afe
defines a DefaultErrorEncoder, refactor the handling of errorEncoder …
suekto-andreas Jan 28, 2019
6a69716
refactor Server into Handler
suekto-andreas Jan 28, 2019
5a7cbf4
remove wrapper
suekto-andreas Jan 28, 2019
e831b16
refactor variable s into h
suekto-andreas Jan 28, 2019
1be9848
simplify the return of errorEncoder
suekto-andreas Jan 28, 2019
4f01057
Update transport/awslambda/handler.go
fahrradflucht Jan 29, 2019
a04bdd6
Update transport/awslambda/handler.go
fahrradflucht Jan 29, 2019
40f8b1a
Update transport/awslambda/handler.go
fahrradflucht Jan 29, 2019
1a31338
DefaultErrorEncoder unit test
suekto-andreas Jan 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions transport/awslambda/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package awslambda provides an AWS Lambda transport layer.
package awslambda
16 changes: 16 additions & 0 deletions transport/awslambda/encode_decode.go
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.
Copy link
Member

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?

Copy link
Contributor Author

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.

type ErrorEncoder func(ctx context.Context, err error) ([]byte, error)
120 changes: 120 additions & 0 deletions transport/awslambda/handler.go
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) {

Choose a reason for hiding this comment

The 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 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add it in 1a31338 ☺️pretty important for future safe-guard from accidental breaking changes.

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
}
Loading