Skip to content

RFC: Event Handler for API Gateway Web Sockets #3191

@walmsles

Description

@walmsles

Is this related to an existing feature request or issue?

#1165

Which Powertools for AWS Lambda (Python) utility does this relate to?

Event Handler - REST API

Summary

To provide an Event Handler class to enable the implementation of Web Socket routes for API Gateway Web Socket connections.

Background

Web Socket connections are serviced by API routes that behave in particular ways. I recently wrote about this in an article here. The implementation of the Web Socket class should take into account current Web Socket route nuances and enable customers to create Web Socket implementations quickly and with significantly less boilerplate code and with a similar implementation pattern - at the end of they day it is all about defining routes.

Use case

Enabling implementation of API Gateway Web Socket routes using exactly the same style of code as existing API Gateway implementations and enabling familiar handling of Web Socket routes.

Proposal

before:

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()

@tracer.capture_method
def socket_connect():
    // do connection processing
    return {"statusCode": 200}

@tracer.capture_method
def order_notify():

    // do notify processing
    return {
         "statusCode": 200,
         "body": "order# 1234 Created",
    }

@tracer.capture_method
def socket_disconnect():

    // do connection processing

    return {"statusCode": 200}

# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
    if event.requestContext.routeKey == '$connect':
        return socket_connect(event, context)
    elif event.requestContext.routeKey == '$disconnect': 
        return socket_disconnect(event, context)
    else:
        return route_not_found(event, context)

after:

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayWebsocketResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = APIGatewayWebsocketResolver()


@app.route("$connect")
@tracer.capture_method
def socket_connect():
    // do connection processing
    return {"statusCode": 200}

@app.route("order/notify")
@tracer.capture_method
def order_notify():

    // do connection processing
    return {
         "statusCode": 200,
         "body": "order# 1234 Created",
    }

@app.route("$disconnect")
@tracer.capture_method
def socket_disconnect():

    // do connection processing

    return {"statusCode": 200}

@app.route("$disconnect")
@tracer.capture_method
def socket_disconnect():

    // do connection processing

    return {"statusCode": 200}

# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
    return app.resolve(event, context)

Out of scope

The implementation must be specifically focused on route definitions and handlers with utilities for common use-cases only and not touch any cloud infrastructure (as per tenets).

Potential challenges

End-to-End testing is one potential challenge - unsure if this style of interface exists, so async testing with live infrastructure will require careful thought and planning.

We need to carefully navigate route definition and look at what we do when no $connect route exists (which implies NO authorisation/authentication in the API gateway solution). Infrastructure as code tools should cater for this nuance, but we need to decide how to handle this situation specifically, which creates a cloud vulnerability.

We need to consider route definition carefully and decide on where this fits in the class hierarchy. Potentially this should exist separately from APIGatewayResolvers, given there are no HTTP Methods and other characteristics. There are Headers but only inbound within the actual event - never outbound.

Lots to think about and discuss, I would like to see a familiar Resolver style implementation for WebSocket routes - they are analogous to APIgatewayResolver routes in many ways. Custom and $default routes are capable of returning an actual response which is sent back to the calling web socket connection in the same way as any other broadcast message.

Dependencies and Integrations

No response

Alternative solutions

Custom implementation with boilerplate code.

Acknowledgment

Metadata

Metadata

Labels

RFCneed-customer-feedbackRequires more customers feedback before making or revisiting a decision

Type

No type

Projects

Status

Closed

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions