Skip to content

feat(event-handler): Add AppSync handler decorator #363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ce80a90
feat(event-handler): Add AppSync handler decorator
michaelbrewer Mar 25, 2021
c7709bf
test(event-handler): Use pathlib
michaelbrewer Mar 25, 2021
f145c04
fix(tracer): Correct type hint for MyPy
michaelbrewer Mar 25, 2021
f4c07aa
Merge branch 'develop' into feat-event-handler-appsync
michaelbrewer Mar 25, 2021
2b82642
docs(event-handler): Initial markdown docs
michaelbrewer Mar 26, 2021
9f4e3e8
feat(event-handler): Add an implicit appsync handler
michaelbrewer Mar 26, 2021
3f664d7
docs(event-handler): Add implicit handler example
michaelbrewer Mar 26, 2021
4f43365
docs(event-handler): Add full amplify example
michaelbrewer Mar 26, 2021
36b088e
chore(event-handler): Add more docs
michaelbrewer Mar 27, 2021
347091f
chore(event-handler): Add current_event
michaelbrewer Mar 29, 2021
d969e98
Merge branch 'develop' into feat-event-handler-appsync
michaelbrewer Mar 29, 2021
7d98715
refactor(event-handler): Remove include_event and incluce_context opt…
michaelbrewer Mar 30, 2021
240b0a6
chore: bump ci
michaelbrewer Mar 30, 2021
f009f56
Merge branch 'develop' into feat-event-handler-appsync
michaelbrewer Mar 30, 2021
dc93055
Merge branch 'develop' into feat-event-handler-appsync
michaelbrewer Mar 30, 2021
8f04851
refactor(event-handler): Move to up to
michaelbrewer Mar 30, 2021
daa56f9
chore(event-handler): Add debug logging to appsync resolver
michaelbrewer Mar 30, 2021
02818db
docs(event-handler): Add more detailed example to docstring
michaelbrewer Mar 30, 2021
e778cf0
chore(event-handler): Rename to _get_resolver
michaelbrewer Mar 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion aws_lambda_powertools/utilities/data_classes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from aws_lambda_powertools.utilities.data_classes.appsync_resolver_event import AppSyncResolverEvent
"""
Event Source Data Classes utility provides classes self-describing Lambda event sources.
"""

from .alb_event import ALBEvent
from .api_gateway_proxy_event import APIGatewayProxyEvent, APIGatewayProxyEventV2
from .appsync_resolver_event import AppSyncResolverEvent
from .cloud_watch_logs_event import CloudWatchLogsEvent
from .connect_contact_flow_event import ConnectContactFlowEvent
from .dynamo_db_stream_event import DynamoDBStreamEvent
Expand Down

This file was deleted.

7 changes: 7 additions & 0 deletions aws_lambda_powertools/utilities/event_handler/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
Event handler decorators for common Lambda events
"""

from .appsync import AppSyncResolver

__all__ = ["AppSyncResolver"]
145 changes: 145 additions & 0 deletions aws_lambda_powertools/utilities/event_handler/appsync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
from typing import Any, Dict

from aws_lambda_powertools.utilities.data_classes import AppSyncResolverEvent
from aws_lambda_powertools.utilities.typing import LambdaContext


class AppSyncResolver:
"""
AppSync resolver decorator

Example
-------

**Sample usage**

from aws_lambda_powertools.utilities.data_classes import AppSyncResolverEvent
from aws_lambda_powertools.utilities.event_handler import AppSyncResolver

app = AppSyncResolver()

@app.resolver(type_name="Query", field_name="listLocations", include_event=True)
def list_locations(event: AppSyncResolverEvent, page: int = 0, size: int = 10):
# Your logic to fetch locations
...

@app.resolver(type_name="Merchant", field_name="extraInfo", include_event=True)
def get_extra_info(event: AppSyncResolverEvent):
# Can use "event.source" to filter within the parent context
...

@app.resolver(field_name="commonField")
def common_field():
# Would match all fieldNames matching 'commonField'
...
"""

current_event: AppSyncResolverEvent
lambda_context: LambdaContext

def __init__(self):
self._resolvers: dict = {}

def resolver(
self,
type_name: str = "*",
field_name: str = None,
include_event: bool = False,
include_context: bool = False,
**kwargs,
):
"""Registers the resolver for field_name

Parameters
----------
type_name : str
Type name
field_name : str
Field name
include_event: bool
Whether to include the lambda event
include_context: bool
Whether to include the lambda context
kwargs :
Extra options via kwargs
"""

def register_resolver(func):
kwargs["include_event"] = include_event
kwargs["include_context"] = include_context
self._resolvers[f"{type_name}.{field_name}"] = {
"func": func,
"config": kwargs,
}
return func

return register_resolver

def resolve(self, _event: dict, context: LambdaContext) -> Any:
"""Resolve field_name

Parameters
----------
_event : dict
Lambda event
context : LambdaContext
Lambda context

Returns
-------
Any
Returns the result of the resolver

Raises
-------
ValueError
If we could not find a field resolver
"""
self.current_event = AppSyncResolverEvent(_event)
self.lambda_context = context
resolver, config = self._resolver(self.current_event.type_name, self.current_event.field_name)
kwargs = self._kwargs(config)
return resolver(**kwargs)

def _resolver(self, type_name: str, field_name: str) -> tuple:
"""Find resolver for field_name

Parameters
----------
type_name : str
Type name
field_name : str
Field name

Returns
-------
tuple
callable function and configuration
"""
full_name = f"{type_name}.{field_name}"
resolver = self._resolvers.get(full_name, self._resolvers.get(f"*.{field_name}"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add a comment or a debug statement here on *.{field_name} mechanics or in the docstring? I'm sure I'll forget this later.

For example, what if someone wants to resolve all fields for a given type?

if not resolver:
raise ValueError(f"No resolver found for '{full_name}'")
return resolver["func"], resolver["config"]

def _kwargs(self, config: dict) -> Dict[str, Any]:
"""Get the keyword arguments
Parameters
----------
config : dict
Configuration settings
Returns
-------
dict
Returns keyword arguments
"""
kwargs = {**self.current_event.arguments}
if config.get("include_event", False):
kwargs["event"] = self.current_event
if config.get("include_context", False):
kwargs["context"] = self.lambda_context
return kwargs

def __call__(self, event, context) -> Any:
"""Implicit lambda handler which internally calls `resolve`"""
return self.resolve(event, context)
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ aws serverlessrepo list-application-versions \
| [Event source data classes](./utilities/data_classes) | Data classes describing the schema of common Lambda event triggers
| [Parser](./utilities/parser) | Data parsing and deep validation using Pydantic
| [Idempotency](./utilities/idempotency) | Idempotent Lambda handler
| [Event handler](./utilities/event_handler) | Event handler decorators for common Lambda events

## Environment variables

Expand Down
3 changes: 1 addition & 2 deletions docs/utilities/data_classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ title: Event Source Data Classes
description: Utility
---

Event Source Data Classes utility provides classes self-describing Lambda event sources, including API decorators when
applicable.
Event Source Data Classes utility provides classes self-describing Lambda event sources.

## Key Features

Expand Down
Loading