From c83699c938a36c6d111f9837be9295184efeeb2e Mon Sep 17 00:00:00 2001 From: Matteo Date: Wed, 20 Feb 2019 20:45:23 +0100 Subject: [PATCH] ApiGw websocket events (#159) * apigw websocket event testdata * Add event for ApiGW Websocket integration * typo in struct name * fixed test event * matching apigw testdata * duplicated identidy data * duplicated json field requestTimeEpoch * fixed test request json order * Fixes suggestions from pr: aws/aws-lambda-go#159 issue: aws/aws-lambda-go#154 * ExtendedRequestId -> ExtendedRequestID * Change type of Authorizer to interface{} * Update apigw.go changed wrong `Authorizer` --- events/apigw.go | 44 ++++++++ events/apigw_test.go | 27 +++++ events/testdata/apigw-websocket-request.json | 106 +++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 events/testdata/apigw-websocket-request.json diff --git a/events/apigw.go b/events/apigw.go index 72e68c62..520a02c8 100644 --- a/events/apigw.go +++ b/events/apigw.go @@ -57,6 +57,50 @@ type APIGatewayRequestIdentity struct { User string `json:"user"` } +// APIGatewayWebsocketProxyRequest contains data coming from the API Gateway proxy +type APIGatewayWebsocketProxyRequest struct { + Resource string `json:"resource"` // The resource path defined in API Gateway + Path string `json:"path"` // The url path for the caller + HTTPMethod string `json:"httpMethod"` + Headers map[string]string `json:"headers"` + MultiValueHeaders map[string][]string `json:"multiValueHeaders"` + QueryStringParameters map[string]string `json:"queryStringParameters"` + MultiValueQueryStringParameters map[string][]string `json:"multiValueQueryStringParameters"` + PathParameters map[string]string `json:"pathParameters"` + StageVariables map[string]string `json:"stageVariables"` + RequestContext APIGatewayWebsocketProxyRequestContext `json:"requestContext"` + Body string `json:"body"` + IsBase64Encoded bool `json:"isBase64Encoded,omitempty"` +} + +// APIGatewayWebsocketProxyRequestContext contains the information to identify +// the AWS account and resources invoking the Lambda function. It also includes +// Cognito identity information for the caller. +type APIGatewayWebsocketProxyRequestContext struct { + AccountID string `json:"accountId"` + ResourceID string `json:"resourceId"` + Stage string `json:"stage"` + RequestID string `json:"requestId"` + Identity APIGatewayRequestIdentity `json:"identity"` + ResourcePath string `json:"resourcePath"` + Authorizer interface{} `json:"authorizer"` + HTTPMethod string `json:"httpMethod"` + APIID string `json:"apiId"` // The API Gateway rest API Id + ConnectedAt int64 `json:"connectedAt"` + ConnectionID string `json:"connectionId"` + DomainName string `json:"domainName"` + Error string `json:"error"` + EventType string `json:"eventType"` + ExtendedRequestID string `json:"extendedRequestId"` + IntegrationLatency string `json:"integrationLatency"` + MessageDirection string `json:"messageDirection"` + MessageID interface{} `json:"messageId"` + RequestTime string `json:"requestTime"` + RequestTimeEpoch int64 `json:"requestTimeEpoch"` + RouteKey string `json:"routeKey"` + Status string `json:"status"` +} + // APIGatewayCustomAuthorizerRequestTypeRequestIdentity contains identity information for the request caller. type APIGatewayCustomAuthorizerRequestTypeRequestIdentity struct { APIKey string `json:"apiKey"` diff --git a/events/apigw_test.go b/events/apigw_test.go index ac1f0766..3749bdb4 100644 --- a/events/apigw_test.go +++ b/events/apigw_test.go @@ -127,6 +127,33 @@ func TestApiGatewayCustomAuthorizerRequestTypeRequestMalformedJson(t *testing.T) test.TestMalformedJson(t, APIGatewayCustomAuthorizerRequestTypeRequest{}) } +func TestApiGatewayWebsocketRequestMarshaling(t *testing.T) { + + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/apigw-websocket-request.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into Go object + var inputEvent APIGatewayWebsocketProxyRequest + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +} + +func TestApiGatewayWebsocketRequestMalformedJson(t *testing.T) { + test.TestMalformedJson(t, APIGatewayWebsocketProxyRequest{}) +} + func TestApiGatewayCustomAuthorizerResponseMarshaling(t *testing.T) { // read json from file diff --git a/events/testdata/apigw-websocket-request.json b/events/testdata/apigw-websocket-request.json new file mode 100644 index 00000000..821ffc66 --- /dev/null +++ b/events/testdata/apigw-websocket-request.json @@ -0,0 +1,106 @@ +{ + "resource": "/{proxy+}", + "path": "/hello/world", + "httpMethod": "POST", + "headers": { + "Accept": "*/*", + "Accept-Encoding": "gzip, deflate", + "cache-control": "no-cache", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Content-Type": "application/json", + "headerName": "headerValue", + "Host": "gy415nuibc.execute-api.us-east-1.amazonaws.com", + "Postman-Token": "9f583ef0-ed83-4a38-aef3-eb9ce3f7a57f", + "User-Agent": "PostmanRuntime/2.4.5", + "Via": "1.1 d98420743a69852491bbdea73f7680bd.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "pn-PWIJc6thYnZm5P0NMgOUglL1DYtl0gdeJky8tqsg8iS_sgsKD1A==", + "X-Forwarded-For": "54.240.196.186, 54.182.214.83", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "Host": [ + "*.execute-api.eu-central-1.amazonaws.com" + ], + "Sec-WebSocket-Extensions": [ + "permessage-deflate; client_max_window_bits" + ], + "Sec-WebSocket-Key": [ + "*" + ], + "Sec-WebSocket-Version": [ + "13" + ], + "X-Amzn-Trace-Id": [ + "Root=*" + ], + "X-Forwarded-For": [ + "*.*.*.*" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "queryStringParameters": { + "name": "me" + }, + "multiValueQueryStringParameters": { + "name": ["me"] + }, + "pathParameters": { + "proxy": "hello/world" + }, + "stageVariables": { + "stageVariableName": "stageVariableValue" + }, + "requestContext": { + "accountId": "12345678912", + "resourceId": "roq9wj", + "stage": "testStage", + "requestId": "deef4878-7910-11e6-8f14-25afc3e9ae33", + "identity": { + "cognitoIdentityPoolId": "theCognitoIdentityPoolId", + "accountId": "theAccountId", + "cognitoIdentityId": "theCognitoIdentityId", + "caller": "theCaller", + "apiKey": "theApiKey", + "accessKey": "ANEXAMPLEOFACCESSKEY", + "sourceIp": "192.168.196.186", + "cognitoAuthenticationType": "theCognitoAuthenticationType", + "cognitoAuthenticationProvider": "theCognitoAuthenticationProvider", + "userArn": "theUserArn", + "userAgent": "PostmanRuntime/2.4.5", + "user": "theUser" + }, + "resourcePath": "/{proxy+}", + "authorizer": { + "principalId": "admin", + "clientId": 1, + "clientName": "Exata" + }, + "httpMethod": "POST", + "apiId": "gy415nuibc", + "connectedAt": 1547230720092, + "connectionId": "TWegAcC4EowCHnA=", + "domainName": "*.execute-api.eu-central-1.amazonaws.com", + "error": "*", + "eventType": "CONNECT", + "extendedRequestId": "TWegAcC4EowCHnA=", + "integrationLatency": "123", + "messageDirection": "IN", + "messageId": null, + "requestTime": "07/Jan/2019:09:20:57 +0000", + "requestTimeEpoch": 0, + "routeKey": "$connect", + "status": "*" + }, + "body": "{\r\n\t\"a\": 1\r\n}" +}