powertools-lambda-python icon indicating copy to clipboard operation
powertools-lambda-python copied to clipboard

Feature request: APIGatewayRestResolver decorator support for class methods (use case: constructor injection)

Open harwoodjp opened this issue 3 years ago • 4 comments

Use case

I'd like to decorate class methods with APIGatewayRestResolver's router.

Particularly, I want to use constructor injection in my app. Support dependency injection in lambda parameters is good prerequisite reading.

Here is illustrative code. We have a GET that queries Dynamo with animal_id and returns a JSON response:

class App:
    resolver = APIGatewayRestResolver()

    def __init__(
            self,
            dynamo_client: DynamoClient = DynamoClient(ANIMAL_TABLE)
    ):
        self.dynamo_client = dynamo_client

    @resolver.get("/animal/<animal_id>")
    def get_animal(self, animal_id):
        result = self.dynamo_client.get_item_by_key("animal_id", animal_id)
        payload = json.dumps(result.get("data", []))
        return Response(
            status_code=HTTPStatus.OK,
            content_type=content_types.APPLICATION_JSON,
            body=payload,
        )

def lambda_handler(event, context):
    return App().resolver.resolve(event, context)

Currently I get the following error:

missing 1 required positional argument: 'self'

which indicates self argument isn't being passed. So I believe APIGatewayRestResolver router can't decorate class methods.

Solution/User Experience

Solution is probably:

  • Configure the decorator to pass self

Alternative solutions

Another solution is to simply use method injection as described by @heitorlessa in Support dependency injection in lambda parameters. This negates the benefits of constructor injection, which is useful when multiple methods share a client, for example.

Acknowledgment

harwoodjp avatar Nov 08 '22 18:11 harwoodjp

Thanks for opening your first issue here! We'll come back to you as soon as we can. In the meantime, check out the #python channel on our AWS Lambda Powertools Discord: Invite link

boring-cyborg[bot] avatar Nov 08 '22 18:11 boring-cyborg[bot]

Hey @harwoodjp if you have the bandwidth, I'd welcome a PR for this.

The issue is that route method was implement as a closure not an actual decorator that could handle both functions and classes (it's different for classes, specially when preserving identity).

It's something I've been wanting to refactor but didn't get the bandwidth yet. Class support decorators is becoming a new ask so we should support this, expand the Middleware Factory utility, and more recently allow the new Middleware support with Classes in mind.

Appreciate any help here and can guide any step if you have the bandwidth too.

Thanks a lot!

heitorlessa avatar Nov 08 '22 19:11 heitorlessa

Adding 'triage' label so we revisit it in upcoming iterations

heitorlessa avatar Jan 31 '23 08:01 heitorlessa

I have completed an initial POC pass at API Middleware for ApiRestResolver - the middleware supports any python Callable structure including a class implementing the __call__ method. Maybe this would address the feature request here? I feel middleware addresses a lot of issues currently in the log that are old so commenting here to try and collate them all.

PR: #2917

walmsles avatar Aug 03 '23 12:08 walmsles