Skip to content

Commit 1e404ec

Browse files
committed
Merge branch 'develop'
2 parents 9189ffb + 96f8a2a commit 1e404ec

17 files changed

+4434
-314
lines changed

aws/adaptor.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@ import (
44
"context"
55
"fmt"
66
"github.com/aws/aws-lambda-go/lambda"
7+
"github.com/aws/aws-lambda-go/lambda/handlertrace"
78
"github.com/yacchi/lambda-http-adaptor/registry"
89
"github.com/yacchi/lambda-http-adaptor/types"
910
"net/http"
1011
"os"
1112
)
1213

14+
var DEBUGDumpPayload = os.Getenv("DEBUG_DUMP_PAYLOAD")
15+
var LambdaInvokeMode = os.Getenv("LAMBDA_INVOKE_MODE")
16+
17+
// WebsocketResponseMode
18+
// * return - use lambda return value as response
19+
// * post_to_connection - use PostToConnection API to send response
20+
var WebsocketResponseMode = os.Getenv("WEBSOCKET_RESPONSE_MODE")
21+
1322
type LambdaIntegrationType int
1423

1524
const (
@@ -18,13 +27,20 @@ const (
1827
APIGatewayWebsocketIntegration
1928
APIGatewayHTTPIntegration
2029
ALBTargetGroupIntegration
30+
LambdaFunctionURLIntegration
2131
)
2232

2333
type integrationTypeChecker struct {
2434
// 'resource' parameter only has REST API event.
2535
Resource *string `json:"resource"`
26-
// 'version' parameter only has HTTP API mode event.
36+
// 'version' only has API Gateway V2 payload (HTTP API mode or Lambda FunctionURL).
2737
Version *string `json:"version"`
38+
// 'pathParameters' parameter only has API Gateway V2 payload.
39+
// However, it is always nil for Function URLs.
40+
PathParameters map[string]string `json:"pathParameters"`
41+
// 'routeKey' parameter only has API Gateway V2 payload.
42+
// However, in the case of Function URLs, it is always $default.
43+
RouteKey string `json:"routeKey"`
2844
// 'http_method' parameter has event of API Gateway REST API mode and ALB target group mode.
2945
// However, ALB target group mode has not 'resource' parameter.
3046
HTTPMethod *string `json:"httpMethod"`
@@ -47,6 +63,9 @@ func (t integrationTypeChecker) IntegrationType() LambdaIntegrationType {
4763
return APIGatewayWebsocketIntegration
4864
}
4965
if t.Version != nil {
66+
if t.RouteKey == "$default" && t.PathParameters == nil {
67+
return LambdaFunctionURLIntegration
68+
}
5069
return APIGatewayHTTPIntegration
5170
}
5271
if t.HTTPMethod != nil && t.Resource == nil {
@@ -69,11 +88,22 @@ func LambdaDetector() bool {
6988
}
7089

7190
type LambdaAdaptor struct {
72-
h lambda.Handler
91+
h *LambdaHandler
7392
}
7493

7594
func (l LambdaAdaptor) ListenAndServe() error {
76-
lambda.Start(l.h)
95+
ctx := context.Background()
96+
if DEBUGDumpPayload != "" && (DEBUGDumpPayload == "1" || DEBUGDumpPayload == "true") {
97+
ctx = handlertrace.NewContext(ctx, handlertrace.HandlerTrace{
98+
RequestEvent: func(ctx context.Context, payload interface{}) {
99+
fmt.Printf("Request payload: %s\n", payload)
100+
},
101+
ResponseEvent: func(ctx context.Context, payload interface{}) {
102+
fmt.Printf("Response payload: %+v\n", payload)
103+
},
104+
})
105+
}
106+
lambda.StartHandlerFunc(l.h.Invoke, lambda.WithContext(ctx))
77107
return nil
78108
}
79109

aws/alb_target_group.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ func NewALBTargetGroupRequest(ctx context.Context, e *events.ALBTargetGroupReque
3131

3232
if e.MultiValueHeaders != nil {
3333
multiValue = true
34-
header = e.MultiValueHeaders
34+
for key, values := range e.MultiValueHeaders {
35+
for _, value := range values {
36+
header.Add(key, value)
37+
}
38+
}
3539
} else if e.Headers != nil {
3640
for k, v := range e.Headers {
3741
header.Set(k, v)

aws/api_gateway_rest.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,15 @@ func NewRESTAPIRequest(ctx context.Context, e *events.APIGatewayProxyRequest) (r
2727
var (
2828
body *bytes.Buffer
2929
header = make(http.Header)
30-
query = make(url.Values)
3130
)
3231

3332
if e.MultiValueHeaders != nil {
3433
multiValue = true
35-
header = e.MultiValueHeaders
34+
for key, values := range e.MultiValueHeaders {
35+
for _, value := range values {
36+
header.Add(key, value)
37+
}
38+
}
3639
} else if e.Headers != nil {
3740
for k, v := range e.Headers {
3841
header.Set(k, v)
@@ -49,15 +52,11 @@ func NewRESTAPIRequest(ctx context.Context, e *events.APIGatewayProxyRequest) (r
4952
u.Host = header.Get(types.HTTPHeaderHost)
5053

5154
if e.MultiValueQueryStringParameters != nil {
52-
query = e.MultiValueQueryStringParameters
55+
u.RawQuery = utils.JoinMultiValueQueryParameters(e.MultiValueQueryStringParameters)
5356
} else if e.QueryStringParameters != nil {
54-
for k, v := range e.QueryStringParameters {
55-
query.Set(k, v)
56-
}
57+
u.RawQuery = utils.JoinQueryParameters(e.QueryStringParameters)
5758
}
5859

59-
u.RawQuery = query.Encode()
60-
6160
// build body reader
6261
if e.IsBase64Encoded {
6362
b, err := base64.StdEncoding.DecodeString(e.Body)

aws/api_gateway_websocket.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ func NewWebsocketRequest(ctx context.Context, e *events.APIGatewayWebsocketProxy
4444

4545
if e.MultiValueHeaders != nil {
4646
multiValue = true
47-
header = e.MultiValueHeaders
47+
for key, values := range e.MultiValueHeaders {
48+
for _, value := range values {
49+
header.Add(key, value)
50+
}
51+
}
4852
} else if e.Headers != nil {
4953
for k, v := range e.Headers {
5054
header.Set(k, v)
@@ -64,11 +68,9 @@ func NewWebsocketRequest(ctx context.Context, e *events.APIGatewayWebsocketProxy
6468
}
6569

6670
if e.MultiValueQueryStringParameters != nil {
67-
query = e.MultiValueQueryStringParameters
71+
u.RawQuery = utils.JoinMultiValueQueryParameters(e.MultiValueQueryStringParameters)
6872
} else if e.QueryStringParameters != nil {
69-
for k, v := range e.QueryStringParameters {
70-
query.Set(k, v)
71-
}
73+
u.RawQuery = utils.JoinQueryParameters(e.QueryStringParameters)
7274
}
7375

7476
if 0 < len(query) {

aws/lambda.go

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"github.com/aws/aws-lambda-go/events"
8-
"github.com/aws/aws-lambda-go/lambda"
9-
"github.com/aws/aws-lambda-go/lambda/handlertrace"
8+
"github.com/aws/aws-lambda-go/lambdaurl"
109
"github.com/aws/aws-sdk-go-v2/aws"
1110
"github.com/aws/aws-sdk-go-v2/config"
1211
"github.com/aws/aws-sdk-go/aws/session"
@@ -46,24 +45,28 @@ func WithoutNonHTTPEventPassThrough() LambdaHandlerOption {
4645
}
4746

4847
type LambdaHandler struct {
49-
httpHandler http.Handler
50-
sessProv SDKSessionProvider
51-
sess *session.Session
52-
confProv SDKConfigProvider
53-
conf *aws.Config
54-
apiGW APIGatewayManagementAPI
55-
wsPathPrefix string
56-
nonHTTPEventPath string
48+
httpHandler http.Handler
49+
sessProv SDKSessionProvider
50+
sess *session.Session
51+
confProv SDKConfigProvider
52+
conf *aws.Config
53+
apiGW APIGatewayManagementAPI
54+
wsPathPrefix string
55+
nonHTTPEventPath string
56+
invokeLambdaWithStream func(ctx context.Context, request *events.LambdaFunctionURLRequest) (*events.LambdaFunctionURLStreamingResponse, error)
5757
}
5858

59-
func NewLambdaHandlerWithOption(h http.Handler, options []interface{}) lambda.Handler {
59+
type HandlerFunc func(ctx context.Context, payload json.RawMessage) (res any, err error)
60+
61+
func NewLambdaHandlerWithOption(h http.Handler, options []interface{}) *LambdaHandler {
6062
handler := &LambdaHandler{
6163
httpHandler: h,
6264
confProv: func(ctx context.Context) (aws.Config, error) {
6365
return config.LoadDefaultConfig(ctx)
6466
},
65-
wsPathPrefix: DefaultWebsocketPathPrefix,
66-
nonHTTPEventPath: DefaultNonHTTPEventPath,
67+
wsPathPrefix: DefaultWebsocketPathPrefix,
68+
nonHTTPEventPath: DefaultNonHTTPEventPath,
69+
invokeLambdaWithStream: lambdaurl.Wrap(h),
6770
}
6871

6972
for _, opt := range options {
@@ -75,7 +78,7 @@ func NewLambdaHandlerWithOption(h http.Handler, options []interface{}) lambda.Ha
7578
return handler
7679
}
7780

78-
func NewLambdaHandler(h http.Handler) lambda.Handler {
81+
func NewLambdaHandler(h http.Handler) *LambdaHandler {
7982
return NewLambdaHandlerWithOption(h, nil)
8083
}
8184

@@ -163,7 +166,7 @@ func (l *LambdaHandler) InvokeWebsocketAPI(ctx context.Context, request *events.
163166

164167
routeKey := request.RequestContext.RouteKey
165168

166-
if routeKey == "$connect" || routeKey == "$disconnect" {
169+
if routeKey == "$connect" || routeKey == "$disconnect" || WebsocketResponseMode == "return" {
167170
w := NewResponseWriter()
168171
l.httpHandler.ServeHTTP(w, req)
169172
return RESTAPITargetResponse(w, multiValue)
@@ -178,13 +181,9 @@ func (l *LambdaHandler) InvokeWebsocketAPI(ctx context.Context, request *events.
178181
}
179182
}
180183

181-
func (l *LambdaHandler) Invoke(ctx context.Context, payload []byte) ([]byte, error) {
182-
trace := handlertrace.FromContext(ctx)
183-
184+
func (l *LambdaHandler) Invoke(ctx context.Context, payload json.RawMessage) (res any, err error) {
184185
var (
185186
checker integrationTypeChecker
186-
res interface{}
187-
err error
188187
)
189188

190189
if err = json.Unmarshal(payload, &checker); err != nil {
@@ -196,54 +195,43 @@ func (l *LambdaHandler) Invoke(ctx context.Context, payload []byte) ([]byte, err
196195
if err := json.Unmarshal(payload, event); err != nil {
197196
return nil, err
198197
}
199-
if trace.RequestEvent != nil {
200-
trace.RequestEvent(ctx, payload)
201-
}
202198
res, err = l.InvokeRESTAPI(ctx, event)
203199
case APIGatewayHTTPIntegration:
204200
event := &events.APIGatewayV2HTTPRequest{}
205201
if err := json.Unmarshal(payload, event); err != nil {
206202
return nil, err
207203
}
208-
if trace.RequestEvent != nil {
209-
trace.RequestEvent(ctx, payload)
210-
}
211204
res, err = l.InvokeHTTPAPI(ctx, event)
212205
case ALBTargetGroupIntegration:
213206
event := &events.ALBTargetGroupRequest{}
214207
if err := json.Unmarshal(payload, event); err != nil {
215208
return nil, err
216209
}
217-
if trace.RequestEvent != nil {
218-
trace.RequestEvent(ctx, payload)
219-
}
220210
res, err = l.InvokeALBTargetGroup(ctx, event)
221211
case APIGatewayWebsocketIntegration:
222212
event := &events.APIGatewayWebsocketProxyRequest{}
223213
if err := json.Unmarshal(payload, event); err != nil {
224214
return nil, err
225215
}
226216
res, err = l.InvokeWebsocketAPI(ctx, event)
217+
case LambdaFunctionURLIntegration:
218+
if LambdaInvokeMode == "response_stream" {
219+
event := &events.LambdaFunctionURLRequest{}
220+
if err := json.Unmarshal(payload, event); err != nil {
221+
return nil, err
222+
}
223+
res, err = l.invokeLambdaWithStream(ctx, event)
224+
} else {
225+
event := &events.APIGatewayV2HTTPRequest{}
226+
if err := json.Unmarshal(payload, event); err != nil {
227+
return nil, err
228+
}
229+
res, err = l.InvokeHTTPAPI(ctx, event)
230+
}
227231
default:
228232
res, err = l.HandleNonHTTPEvent(ctx, payload, "application/json")
229233
}
230234
}
231235

232-
if err != nil {
233-
return nil, err
234-
}
235-
236-
if trace.ResponseEvent != nil {
237-
trace.ResponseEvent(ctx, res)
238-
}
239-
240-
if b, ok := res.([]byte); ok {
241-
return b, nil
242-
} else {
243-
if responseBytes, err := json.Marshal(res); err != nil {
244-
return nil, err
245-
} else {
246-
return responseBytes, nil
247-
}
248-
}
236+
return res, err
249237
}

0 commit comments

Comments
 (0)