Skip to content

Commit a386a87

Browse files
authored
feat(parser): add AppSyncResolver model (#6400)
1 parent 5aa107c commit a386a87

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

aws_lambda_powertools/utilities/parser/models/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
RequestContextV2AuthorizerJwt,
2828
RequestContextV2Http,
2929
)
30+
from .appsync import (
31+
AppSyncResolverEventModel,
32+
)
3033
from .bedrock_agent import (
3134
BedrockAgentEventModel,
3235
BedrockAgentModel,
@@ -137,6 +140,7 @@
137140
"AlbModel",
138141
"AlbRequestContext",
139142
"AlbRequestContextData",
143+
"AppSyncResolverEventModel",
140144
"DynamoDBStreamModel",
141145
"EventBridgeModel",
142146
"DynamoDBStreamChangedRecordModel",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from typing import Optional, List, Dict, Union, Any
2+
from pydantic import BaseModel
3+
4+
class AppSyncIamIdentity(BaseModel):
5+
accountId: str
6+
cognitoIdentityPoolId: Optional[str]
7+
cognitoIdentityId: Optional[str]
8+
sourceIp: List[str]
9+
username: str
10+
userArn: str
11+
cognitoIdentityAuthType: Optional[str]
12+
cognitoIdentityAuthProvider: Optional[str]
13+
14+
15+
class AppSyncCognitoIdentity(BaseModel):
16+
sub: str
17+
issuer: str
18+
username: str
19+
claims: Dict[str, Any]
20+
sourceIp: List[str]
21+
defaultAuthStrategy: str
22+
groups: Optional[List[str]]
23+
24+
25+
class AppSyncOidcIdentity(BaseModel):
26+
claims: Dict[str, Any]
27+
issuer: str
28+
sub: str
29+
30+
31+
class AppSyncLambdaIdentity(BaseModel):
32+
resolverContext: Dict[str, Any]
33+
34+
35+
AppSyncIdentity = Union[
36+
AppSyncIamIdentity,
37+
AppSyncCognitoIdentity,
38+
AppSyncOidcIdentity,
39+
AppSyncLambdaIdentity,
40+
]
41+
42+
43+
class AppSyncRequestModel(BaseModel):
44+
domainName: Optional[str]
45+
headers: Dict[str, str]
46+
47+
48+
class AppSyncInfoModel(BaseModel):
49+
selectionSetList: List[str]
50+
selectionSetGraphQL: str
51+
parentTypeName: str
52+
fieldName: str
53+
variables: Dict[str, Any]
54+
55+
56+
class AppSyncPrevModel(BaseModel):
57+
result: Dict[str, Any]
58+
59+
60+
class AppSyncResolverEventModel(BaseModel):
61+
arguments: Dict[str, Any]
62+
identity: Optional[AppSyncIdentity]
63+
source: Optional[Dict[str, Any]]
64+
request: AppSyncRequestModel
65+
info: AppSyncInfoModel
66+
prev: Optional[AppSyncPrevModel]
67+
stash: Dict[str, Any]
68+
69+
70+
AppSyncBatchResolverEventModel = List[AppSyncResolverEventModel]

docs/utilities/parser.md

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ The example above uses `SqsModel`. Other built-in models can be found below.
111111
| **APIGatewayWebSocketMessageEventModel** | Lambda Event Source payload for Amazon API Gateway WebSocket API message body |
112112
| **APIGatewayWebSocketConnectEventModel** | Lambda Event Source payload for Amazon API Gateway WebSocket API $connect message |
113113
| **APIGatewayWebSocketDisconnectEventModel** | Lambda Event Source payload for Amazon API Gateway WebSocket API $disconnect message |
114+
| **AppSyncResolverEventModel** | Lambda Event Source payload for AWS AppSync Resolver |
114115
| **BedrockAgentEventModel** | Lambda Event Source payload for Bedrock Agents |
115116
| **CloudFormationCustomResourceCreateModel** | Lambda Event Source payload for AWS CloudFormation `CREATE` operation |
116117
| **CloudFormationCustomResourceUpdateModel** | Lambda Event Source payload for AWS CloudFormation `UPDATE` operation |
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"typeName": "Merchant",
3+
"fieldName": "locations",
4+
"arguments": {
5+
"page": 2,
6+
"size": 1,
7+
"name": "value"
8+
},
9+
"identity": {
10+
"claims": {
11+
"sub": "07920713-4526-4642-9c88-2953512de441",
12+
"iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_POOL_ID",
13+
"aud": "58rc9bf5kkti90ctmvioppukm9",
14+
"event_id": "7f4c9383-abf6-48b7-b821-91643968b755",
15+
"token_use": "id",
16+
"auth_time": 1615366261,
17+
"name": "Michael Brewer",
18+
"exp": 1615369861,
19+
"iat": 1615366261
20+
},
21+
"defaultAuthStrategy": "ALLOW",
22+
"groups": null,
23+
"issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_POOL_ID",
24+
"sourceIp": ["11.215.2.22"],
25+
"sub": "07920713-4526-4642-9c88-2953512de441",
26+
"username": "mike"
27+
},
28+
"source": {
29+
"name": "Value",
30+
"nested": {
31+
"name": "value",
32+
"list": []
33+
}
34+
},
35+
"request": {
36+
"headers": {
37+
"x-forwarded-for": "11.215.2.22, 64.44.173.11",
38+
"cloudfront-viewer-country": "US",
39+
"cloudfront-is-tablet-viewer": "false",
40+
"via": "2.0 SOMETHING.cloudfront.net (CloudFront)",
41+
"cloudfront-forwarded-proto": "https",
42+
"origin": "https://console.aws.amazon.com",
43+
"content-length": "156",
44+
"accept-language": "en-US,en;q=0.9",
45+
"host": "SOMETHING.appsync-api.us-east-1.amazonaws.com",
46+
"x-forwarded-proto": "https",
47+
"sec-gpc": "1",
48+
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
49+
"accept": "*/*",
50+
"cloudfront-is-mobile-viewer": "false",
51+
"cloudfront-is-smarttv-viewer": "false",
52+
"accept-encoding": "gzip, deflate, br",
53+
"referer": "https://console.aws.amazon.com/",
54+
"content-type": "application/json",
55+
"sec-fetch-mode": "cors",
56+
"x-amz-cf-id": "Fo5VIuvP6V6anIEt62WzFDCK45mzM4yEdpt5BYxOl9OFqafd-WR0cA==",
57+
"x-amzn-trace-id": "Root=1-60488877-0b0c4e6727ab2a1c545babd0",
58+
"authorization": "AUTH-HEADER",
59+
"sec-fetch-dest": "empty",
60+
"x-amz-user-agent": "AWS-Console-AppSync/",
61+
"cloudfront-is-desktop-viewer": "true",
62+
"sec-fetch-site": "cross-site",
63+
"x-forwarded-port": "443"
64+
},
65+
"domainName": "SOMETHING.appsync-api.us-east-1.amazonaws.com"
66+
},
67+
"prev": {
68+
"result": {}
69+
},
70+
"info": {
71+
"selectionSetList": ["id", "field1", "field2"],
72+
"selectionSetGraphQL": "{\n id\n field1\n field2\n}",
73+
"parentTypeName": "Merchant",
74+
"fieldName": "locations",
75+
"variables": {}
76+
},
77+
"stash": {}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import pytest
2+
3+
from aws_lambda_powertools.utilities.parser import parse, ValidationError
4+
from aws_lambda_powertools.utilities.parser.models import AppSyncResolverEventModel
5+
from tests.functional.utils import load_event
6+
7+
def test_appsync_event_model_parses_successfully():
8+
"""
9+
Validate that a valid AppSync resolver event is correctly parsed by the model.
10+
"""
11+
event = load_event("appsync_resolver_event.json")
12+
parsed_event = parse(event=event, model=AppSyncResolverEventModel)
13+
14+
assert parsed_event.arguments["page"] == 2
15+
assert parsed_event.identity.username == "mike"
16+
assert parsed_event.request.headers["host"].endswith("appsync-api.us-east-1.amazonaws.com")
17+
assert parsed_event.info.fieldName == "locations"
18+
assert parsed_event.info.parentTypeName == "Merchant"
19+
20+
21+
def test_appsync_event_model_invalid_payload_raises():
22+
"""
23+
Validate that parsing an invalid AppSync resolver event payload raises a ValidationError.
24+
"""
25+
invalid_event = {"invalid": "event"}
26+
with pytest.raises(ValidationError):
27+
parse(event=invalid_event, model=AppSyncResolverEventModel)

0 commit comments

Comments
 (0)