Skip to content

Commit adcda91

Browse files
Fix a regression in AppSyncResolver
1 parent 8933312 commit adcda91

File tree

5 files changed

+131
-9
lines changed

5 files changed

+131
-9
lines changed

aws_lambda_powertools/event_handler/appsync.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ def __init__(self):
4949
super().__init__()
5050
self.context = {} # early init as customers might add context before event resolution
5151

52-
self.current_batch_event: List[AppSyncResolverEvent] = []
53-
self.current_event: Optional[AppSyncResolverEvent] = None
54-
self.lambda_context: Optional[LambdaContext] = None
55-
5652
def __call__(
5753
self,
5854
event: dict,
@@ -139,10 +135,13 @@ def lambda_handler(event, context):
139135
"""
140136

141137
self.lambda_context = context
138+
Router.lambda_context = context
142139

143140
if isinstance(event, list):
141+
Router.current_batch_event = [data_model(e) for e in event]
144142
response = self._call_batch_resolver(event=event, data_model=data_model)
145143
else:
144+
Router.current_event = data_model(event)
146145
response = self._call_single_resolver(event=event, data_model=data_model)
147146

148147
self.clear_context()
@@ -162,7 +161,6 @@ def _call_single_resolver(self, event: dict, data_model: Type[AppSyncResolverEve
162161

163162
logger.debug("Processing direct resolver event")
164163

165-
self.current_event = data_model(event)
166164
resolver = self._resolver_registry.find_resolver(self.current_event.type_name, self.current_event.field_name)
167165
if not resolver:
168166
raise ValueError(f"No resolver found for '{self.current_event.type_name}.{self.current_event.field_name}'")
@@ -309,7 +307,6 @@ def _call_batch_resolver(self, event: List[dict], data_model: Type[AppSyncResolv
309307
"""
310308
logger.debug("Processing batch resolver event")
311309

312-
self.current_batch_event = [data_model(e) for e in event]
313310
type_name, field_name = self.current_batch_event[0].type_name, self.current_batch_event[0].field_name
314311

315312
resolver = self._batch_resolver_registry.find_resolver(type_name, field_name)

aws_lambda_powertools/event_handler/graphql_appsync/router.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
from typing import Callable, Optional
1+
from typing import Callable, List, Optional
22

33
from aws_lambda_powertools.event_handler.graphql_appsync._registry import ResolverRegistry
44
from aws_lambda_powertools.event_handler.graphql_appsync.base import BaseRouter
5+
from aws_lambda_powertools.utilities.data_classes.appsync_resolver_event import AppSyncResolverEvent
6+
from aws_lambda_powertools.utilities.typing.lambda_context import LambdaContext
57

68

79
class Router(BaseRouter):
810
context: dict
11+
current_batch_event: List[AppSyncResolverEvent] = []
12+
current_event: Optional[AppSyncResolverEvent] = None
13+
lambda_context: Optional[LambdaContext] = None
914

1015
def __init__(self):
1116
self.context = {} # early init as customers might add context before event resolution

tests/events/appSyncBatchEvent.json

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[
2+
{
3+
"arguments": {
4+
"id": "1"
5+
},
6+
"identity": {
7+
"sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9",
8+
"username": "jdoe"
9+
},
10+
"prev": null,
11+
"info": {
12+
"selectionSetList": [
13+
"id",
14+
"field1",
15+
"field2"
16+
],
17+
"selectionSetGraphQL": "{\n id\n field1\n field2\n}",
18+
"parentTypeName": "Mutation",
19+
"fieldName": "createSomething",
20+
"variables": {}
21+
},
22+
"stash": {}
23+
},
24+
{
25+
"arguments": {
26+
"id": "2"
27+
},
28+
"identity": {
29+
"sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9",
30+
"username": "jdoe"
31+
},
32+
"prev": null,
33+
"info": {
34+
"selectionSetList": [
35+
"id",
36+
"field1",
37+
"field2"
38+
],
39+
"selectionSetGraphQL": "{\n id\n field1\n field2\n}",
40+
"parentTypeName": "Mutation",
41+
"fieldName": "createSomething",
42+
"variables": {}
43+
},
44+
"stash": {}
45+
}
46+
]

tests/functional/event_handler/required_dependencies/appsync/test_appsync_batch_resolvers.py

+38-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from aws_lambda_powertools.utilities.data_classes import AppSyncResolverEvent
99
from aws_lambda_powertools.utilities.typing import LambdaContext
1010
from aws_lambda_powertools.warnings import PowertoolsUserWarning
11+
from tests.functional.utils import load_event
1112

1213

1314
# TESTS RECEIVING THE EVENT PARTIALLY AND PROCESS EACH RECORD PER TIME.
@@ -710,7 +711,6 @@ def create_something(event: List[AppSyncResolverEvent]) -> List: # noqa AA03 VN
710711
assert result == [appsync_event["source"]["id"] for appsync_event in event]
711712

712713
assert app.current_batch_event and len(app.current_batch_event) == len(event)
713-
assert not app.current_event
714714

715715

716716
def test_resolve_async_batch_processing_with_simple_queries_with_aggregate():
@@ -772,7 +772,6 @@ async def create_something(event: List[AppSyncResolverEvent]) -> List: # noqa A
772772
assert result == [appsync_event["source"]["id"] for appsync_event in event]
773773

774774
assert app.current_batch_event and len(app.current_batch_event) == len(event)
775-
assert not app.current_event
776775

777776

778777
def test_resolve_batch_processing_with_aggregate_and_returning_a_non_list():
@@ -907,3 +906,40 @@ def do_something_with_post_id(post_id): ...
907906
# THEN the resolver should raise a InvalidBatchResponse when processing the batch of queries
908907
with pytest.raises(InvalidBatchResponse):
909908
app.resolve(event, LambdaContext())
909+
910+
911+
def test_include_router_access_batch_current_event():
912+
mock_event = load_event("appSyncBatchEvent.json")
913+
914+
# GIVEN An instance of AppSyncResolver, a Router instance, and a resolver function registered with the router
915+
app = AppSyncResolver()
916+
router = Router()
917+
918+
@router.batch_resolver(field_name="createSomething")
919+
def get_user(event: List) -> List:
920+
return [router.current_batch_event[0].identity.sub]
921+
922+
app.include_router(router)
923+
924+
# WHEN we resolve the event
925+
ret = app.resolve(mock_event, {})
926+
927+
# THEN the resolver must be able to return a field in the batch_current_event
928+
assert ret[0] == mock_event[0]["identity"]["sub"]
929+
930+
931+
def test_app_access_batch_current_event():
932+
mock_event = load_event("appSyncBatchEvent.json")
933+
934+
# GIVEN An instance of AppSyncResolver and a resolver function registered with the app
935+
app = AppSyncResolver()
936+
937+
@app.batch_resolver(field_name="createSomething")
938+
def get_user(event: List) -> List:
939+
return [app.current_batch_event[0].identity.sub]
940+
941+
# WHEN we resolve the event
942+
ret = app.resolve(mock_event, {})
943+
944+
# THEN the resolver must be able to return a field in the batch_current_event
945+
assert ret[0] == mock_event[0]["identity"]["sub"]

tests/functional/event_handler/required_dependencies/appsync/test_appsync_single_resolvers.py

+38
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,41 @@ def test_include_router_merges_context():
251251
app.include_router(router)
252252

253253
assert app.context == router.context
254+
255+
256+
def test_include_router_access_current_event():
257+
mock_event = load_event("appSyncDirectResolver.json")
258+
259+
# GIVEN An instance of AppSyncResolver, a Router instance, and a resolver function registered with the router
260+
app = AppSyncResolver()
261+
router = Router()
262+
263+
@router.resolver(field_name="createSomething")
264+
def get_user(id_user: str) -> dict:
265+
return router.current_event.identity.sub
266+
267+
app.include_router(router)
268+
269+
# WHEN we resolve the event
270+
ret = app.resolve(mock_event, {})
271+
272+
# THEN the resolver must be able to return a field in the current_event
273+
assert ret == mock_event["identity"]["sub"]
274+
275+
276+
def test_app_access_current_event():
277+
# Check whether we can handle an example appsync direct resolver
278+
mock_event = load_event("appSyncDirectResolver.json")
279+
280+
# GIVEN An instance of AppSyncResolver and a resolver function registered with the app
281+
app = AppSyncResolver()
282+
283+
@app.resolver(field_name="createSomething")
284+
def get_user(id_user: str) -> dict:
285+
return app.current_event.identity.sub
286+
287+
# WHEN we resolve the event
288+
ret = app.resolve(mock_event, {})
289+
290+
# THEN the resolver must be able to return a field in the current_event
291+
assert ret == mock_event["identity"]["sub"]

0 commit comments

Comments
 (0)