-
Notifications
You must be signed in to change notification settings - Fork 421
feat(appsync): Support AppSyncResolverEvent subclassing #526
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
feat(appsync): Support AppSyncResolverEvent subclassing #526
Conversation
Thanks a lot for your first contribution! Please check out our contributing guidelines and don't hesitate to ask whatever you need. |
Alternatively the annotation 'current_event: AppSyncResolverEvent' could simply be overridden and then utilized via self.annotations'current_event' .. but I'm not sure if annotations is optimized out or how recognized that pattern is. |
Hey @whardier, thanks for the contribution!! Could you share a sample subclass that you created for AppSync event? This will help me understand the use case, and what's potentially missing from the AppSyncEvent class before we add tests for this PR. Thank you |
Sure.. the following is a non-patched solution to provide the custom properties we are accessing from the underlaying _data: from aws_lambda_powertools.utilities.data_classes.appsync_resolver_event import (
AppSyncIdentityCognito,
AppSyncResolverEvent,
)
class CustomAppSyncResolverEvent(AppSyncResolverEvent):
@cached_property
def auth_client_id(self) -> Optional[str]:
auth_client_id: Optional[str] = None
if isinstance(self.identity, AppSyncIdentityCognito):
auth_client_id = self.identity.claims.get("custom:client_id")
return auth_client_id
@cached_property
def auth_user_profile_id(self) -> Optional[str]:
auth_user_profile_id: Optional[str] = None
if isinstance(self.identity, AppSyncIdentityCognito):
auth_user_profile_id = self.identity.claims.get("custom:user_profile_id") or self.identity.sub
return auth_user_profile_id
# ... below to assist with hints
class CustomAppSyncResolver(AppSyncResolver):
current_event: CustomAppSyncResolverEvent
# ... specific enough sample appsync lambda event handler
@appsync.resolver(type_name="Mutation", field_name="logThingUserEvent")
@validate_arguments
@typechecked
def log_thing_user_event(
event_type: ThingUserEventTypeEnum,
measure_reference: Annotated[str, Field(max_length=256)],
measure_source: Annotated[str, Field(max_length=32)] = DEFAULT_THING_USER_EVENT_APPSYNC_METRIC_SOURCE,
):
# ... sample code
auth_client_id: Optional[str] = appsync.current_event.auth_client_id
auth_user_profile_id: Optional[str] = appsync.current_event.auth_user_profile_id
# ... other junk
@core_tracer.capture_lambda_handler
@core_logger.inject_lambda_context(correlation_id_path=correlation_paths.APPSYNC_RESOLVER)
@event_source(data_class=CustomAppSyncResolverEvent)
@typechecked
def appsync_handler(event: CustomAppSyncResolverEvent, context: AnyLambdaContext) -> dict:
# NOTE: Until aws lambda powertools allows for hooks/class references to be part of the resolve method to set up a
# proper current_event with a subclassed dataclass and repeat the innards of the resolve method here (SRS).
appsync.current_event = event
appsync.lambda_context = context
resolver = appsync._get_resolver(event.type_name, event.field_name)
return resolver(**event.arguments)
The proposed patch mimics a bit of the model_class approach seen elsewhere in this project. However a sneaky pattern to do this is as follows and seems to be gaining in popularity: class LibraryDataClass:
pass
class CustomDataClass(LibraryDataClass):
@property
def custom_property(self):
return "custom property data"
class LibraryExecutionClass:
data: LibraryDataClass
def execute(self):
data_class = self.__annotations__["data"]
self.data = data_class()
class CustomExecutionClass(LibraryExecutionClass):
data: CustomDataClass
# >>> custom_executor = CustomExecutionClass()
# >>> custom_executor.execute()
# >>> custom_executor.data.custom_property
# 'custom property data' |
I concerned that using model as a kwarg here would lead to thoughts that this should be a parser.model rather than a dictwrap data_class. I know I would have been confused seeing model. |
That's a great point. I find naming hard because even How does |
…ent-subclass * develop: fix(api-gateway): non-greedy route pattern regex (aws-powertools#533) chore(deps): bump boto3 from 1.18.0 to 1.18.1 (aws-powertools#528) fix(tracer): mypy generic to preserve decorated method signature (aws-powertools#529) fix(parser): Make ApiGateway version, authorizer fields optional (aws-powertools#532) fix(mypy): fixes to resolve no implicit optional errors (aws-powertools#521) chore(deps): bump boto3 from 1.17.110 to 1.18.0 (aws-powertools#527)
Codecov Report
@@ Coverage Diff @@
## develop #526 +/- ##
========================================
Coverage 99.86% 99.86%
========================================
Files 113 113
Lines 4482 4483 +1
Branches 243 243
========================================
+ Hits 4476 4477 +1
Misses 3 3
Partials 3 3
Continue to review full report at Codecov.
|
Sharing my 2 cents here, I'd personally prefer |
Waiting for @whardier before we merge it |
I'm still down with something as simple as data_class (as seen here: My preferences aside. I approve this and thank you for catching the call case and handling the typing the proper way. It was nice being able to submit some thoughts this way and see changes come back as code. |
…ent-subclass * develop: refactor(feature-toggles): Code coverage and housekeeping (aws-powertools#530) feat(logger): add get_correlation_id method (aws-powertools#516)
We'll keep it as Thanks a lot again @whardier |
Awesome work, congrats on your first merged pull request and thank you for helping improve everyone's experience! |
…vent
No outsstanding issue
Description of changes:
Allows for custom subclass of AppSyncResolverEvent data_class to be offered to AppSyncResolver.resolve
Checklist
Breaking change checklist
Not breaking
RFC issue #:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.