Skip to content

Commit

Permalink
Handle disconnect route of Websocket
Browse files Browse the repository at this point in the history
  • Loading branch information
kdnakt committed Jan 20, 2024
1 parent 3a93ed1 commit a8d57a0
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 44 deletions.
88 changes: 45 additions & 43 deletions events/apigw.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,63 +133,65 @@ type APIGatewayV2HTTPResponse struct {

// APIGatewayRequestIdentity contains identity information for the request caller.
type APIGatewayRequestIdentity struct {
CognitoIdentityPoolID string `json:"cognitoIdentityPoolId"`
AccountID string `json:"accountId"`
CognitoIdentityID string `json:"cognitoIdentityId"`
Caller string `json:"caller"`
APIKey string `json:"apiKey"`
APIKeyID string `json:"apiKeyId"`
AccessKey string `json:"accessKey"`
CognitoIdentityPoolID string `json:"cognitoIdentityPoolId,omitempty"`
AccountID string `json:"accountId,omitempty"`
CognitoIdentityID string `json:"cognitoIdentityId,omitempty"`
Caller string `json:"caller,omitempty"`
APIKey string `json:"apiKey,omitempty"`
APIKeyID string `json:"apiKeyId,omitempty"`
AccessKey string `json:"accessKey,omitempty"`
SourceIP string `json:"sourceIp"`
CognitoAuthenticationType string `json:"cognitoAuthenticationType"`
CognitoAuthenticationProvider string `json:"cognitoAuthenticationProvider"`
UserArn string `json:"userArn"` //nolint: stylecheck
CognitoAuthenticationType string `json:"cognitoAuthenticationType,omitempty"`
CognitoAuthenticationProvider string `json:"cognitoAuthenticationProvider,omitempty"`
UserArn string `json:"userArn,omitempty"` //nolint: stylecheck
UserAgent string `json:"userAgent"`
User string `json:"user"`
User string `json:"user,omitempty"`
}

// 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
Resource string `json:"resource,omitempty"` // The resource path defined in API Gateway
Path string `json:"path,omitempty"` // The url path for the caller
HTTPMethod string `json:"httpMethod,omitempty"`
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"`
Headers map[string]string `json:"headers,omitempty"`
MultiValueHeaders map[string][]string `json:"multiValueHeaders,omitempty"`
QueryStringParameters map[string]string `json:"queryStringParameters,omitempty"`
MultiValueQueryStringParameters map[string][]string `json:"multiValueQueryStringParameters,omitempty"`
PathParameters map[string]string `json:"pathParameters,omitempty"`
StageVariables map[string]string `json:"stageVariables,omitempty"`
RequestContext APIGatewayWebsocketProxyRequestContext `json:"requestContext"`
Body string `json:"body"`
IsBase64Encoded bool `json:"isBase64Encoded,omitempty"`
Body string `json:"body,omitempty"`
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"`
AccountID string `json:"accountId,omitempty"`
ResourceID string `json:"resourceId,omitempty"`
Stage string `json:"stage"`
RequestID string `json:"requestId"`
Identity APIGatewayRequestIdentity `json:"identity"`
ResourcePath string `json:"resourcePath,omitempty"`
Authorizer interface{} `json:"authorizer,omitempty"`
HTTPMethod string `json:"httpMethod,omitempty"`
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,omitempty"`
EventType string `json:"eventType"`
ExtendedRequestID string `json:"extendedRequestId"`
IntegrationLatency string `json:"integrationLatency,omitempty"`
MessageDirection string `json:"messageDirection"`
MessageID *string `json:"messageId,omitempty"`
RequestTime string `json:"requestTime"`
RequestTimeEpoch int64 `json:"requestTimeEpoch"`
RouteKey string `json:"routeKey"`
Status string `json:"status,omitempty"`
DisconnectStatusCode int64 `json:"disconnectStatusCode,omitempty"`
DisconnectReason *string `json:"disconnectReason,omitempty"`
}

// APIGatewayCustomAuthorizerRequestTypeRequestIdentity contains identity information for the request caller including certificate information if using mTLS.
Expand Down
46 changes: 46 additions & 0 deletions events/apigw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,52 @@ func TestApiGatewayWebsocketRequestMarshaling(t *testing.T) {
assert.JSONEq(t, string(inputJSON), string(outputJSON))
}

func TestApiGatewayWebsocketRequestSendMessageMarshaling(t *testing.T) {

// read json from file
inputJSON, err := ioutil.ReadFile("./testdata/apigw-websocket-request-send-message.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 TestApiGatewayWebsocketRequestDisconnectMarshaling(t *testing.T) {

// read json from file
inputJSON, err := ioutil.ReadFile("./testdata/apigw-websocket-request-disconnect.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{})
}
Expand Down
35 changes: 35 additions & 0 deletions events/testdata/apigw-websocket-request-disconnect.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"headers": {
"Host": "dl7ptocha9.execute-api.ap-northeast-1.amazonaws.com",
"x-api-key": "",
"X-Forwarded-For": "",
"x-restapi": ""
},
"multiValueHeaders": {
"Host": [ "dl7ptocha9.execute-api.ap-northeast-1.amazonaws.com" ],
"x-api-key": [ "" ],
"X-Forwarded-For": [ "" ],
"x-restapi": [ "" ]
},
"requestContext": {
"routeKey": "$disconnect",
"disconnectStatusCode": 1001,
"eventType": "DISCONNECT",
"extendedRequestId": "R1koeHsUtjMFbRw=",
"requestTime": "20/Jan/2024:11:55:08 +0000",
"messageDirection": "IN",
"disconnectReason": "",
"stage": "prod",
"connectedAt": 1705751697419,
"requestTimeEpoch": 1705751708326,
"identity": {
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"sourceIp": "49.105.91.154"
},
"requestId": "R1koeHsUtjMFbRw=",
"domainName": "dl7ptocha9.execute-api.ap-northeast-1.amazonaws.com",
"connectionId": "R1kmxc2VNjMCFIA=",
"apiId": "dl7ptocha9"
},
"isBase64Encoded": false
}
23 changes: 23 additions & 0 deletions events/testdata/apigw-websocket-request-send-message.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"requestContext": {
"routeKey": "$default",
"messageId": "R1knPc2ntjMCFIA=",
"eventType": "MESSAGE",
"extendedRequestId": "R1knPH17NjMFftw=",
"requestTime": "20/Jan/2024:11:55:00 +0000",
"messageDirection": "IN",
"stage": "prod",
"connectedAt": 1705751697419,
"requestTimeEpoch": 1705751700453,
"identity": {
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
"sourceIp": "49.105.91.154"
},
"requestId": "R1knPH17NjMFftw=",
"domainName": "dl7ptocha9.execute-api.ap-northeast-1.amazonaws.com",
"connectionId": "R1kmxc2VNjMCFIA=",
"apiId": "gy415nuibc"
},
"body": "{\r\n\t\"a\": 1\r\n}",
"isBase64Encoded": false
}
2 changes: 1 addition & 1 deletion events/testdata/apigw-websocket-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"extendedRequestId": "TWegAcC4EowCHnA=",
"integrationLatency": "123",
"messageDirection": "IN",
"messageId": null,
"messageId": "",
"requestTime": "07/Jan/2019:09:20:57 +0000",
"requestTimeEpoch": 0,
"routeKey": "$connect",
Expand Down

0 comments on commit a8d57a0

Please sign in to comment.