Skip to content

Commit 36c489c

Browse files
feat: appsync datasource to eventbus connector (#3311)
Co-authored-by: Slava Senchenko <[email protected]>
1 parent 4fac468 commit 36c489c

File tree

8 files changed

+677
-0
lines changed

8 files changed

+677
-0
lines changed

integration/combination/test_connectors.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def tearDown(self):
6262
("combination/connector_appsync_api_to_lambda",),
6363
("combination/connector_appsync_to_lambda",),
6464
("combination/connector_appsync_to_table",),
65+
("combination/connector_appsync_to_eventbus",),
6566
("combination/connector_function_to_function",),
6667
("combination/connector_restapi_to_function",),
6768
("combination/connector_httpapi_to_function",),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[
2+
{
3+
"LogicalResourceId": "ApiKey",
4+
"ResourceType": "AWS::AppSync::ApiKey"
5+
},
6+
{
7+
"LogicalResourceId": "ApiSchema",
8+
"ResourceType": "AWS::AppSync::GraphQLSchema"
9+
},
10+
{
11+
"LogicalResourceId": "AppSyncApi",
12+
"ResourceType": "AWS::AppSync::GraphQLApi"
13+
},
14+
{
15+
"LogicalResourceId": "AppSyncEventBusDataSource",
16+
"ResourceType": "AWS::AppSync::DataSource"
17+
},
18+
{
19+
"LogicalResourceId": "AppSyncSayHelloResolver",
20+
"ResourceType": "AWS::AppSync::Resolver"
21+
},
22+
{
23+
"LogicalResourceId": "ConnectorPolicy",
24+
"ResourceType": "AWS::IAM::ManagedPolicy"
25+
},
26+
{
27+
"LogicalResourceId": "EventBridgeRole",
28+
"ResourceType": "AWS::IAM::Role"
29+
},
30+
{
31+
"LogicalResourceId": "EventBus",
32+
"ResourceType": "AWS::Events::EventBus"
33+
},
34+
{
35+
"LogicalResourceId": "TriggerFunction",
36+
"ResourceType": "AWS::Lambda::Function"
37+
}
38+
]
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
Resources:
2+
EventBus:
3+
Type: AWS::Events::EventBus
4+
Properties:
5+
Name: !Sub "${AWS::StackName}-EventBus"
6+
7+
EventBridgeRole:
8+
Type: AWS::IAM::Role
9+
Properties:
10+
AssumeRolePolicyDocument:
11+
Version: '2012-10-17'
12+
Statement:
13+
- Effect: Allow
14+
Action:
15+
- sts:AssumeRole
16+
Principal:
17+
Service:
18+
- appsync.amazonaws.com
19+
- lambda.amazonaws.com
20+
21+
AppSyncApi:
22+
Type: AWS::AppSync::GraphQLApi
23+
Properties:
24+
Name: AppSyncApi
25+
AuthenticationType: API_KEY
26+
27+
ApiSchema:
28+
Type: AWS::AppSync::GraphQLSchema
29+
Properties:
30+
ApiId: !GetAtt AppSyncApi.ApiId
31+
Definition: |
32+
type EntryDetails {
33+
ErrorCode: String
34+
ErrorMessage: String
35+
EventId: String!
36+
}
37+
38+
type PutEventsResult {
39+
Entries: [EntryDetails!]!
40+
FailedEntry: Int
41+
}
42+
43+
type Query {
44+
sayHello: PutEventsResult!
45+
}
46+
47+
schema {
48+
query: Query
49+
}
50+
51+
AppSyncEventBusDataSource:
52+
Type: AWS::AppSync::DataSource
53+
Properties:
54+
ApiId: !GetAtt AppSyncApi.ApiId
55+
Name: AppSyncEventBusDataSource
56+
Type: AMAZON_EVENTBRIDGE
57+
ServiceRoleArn: !GetAtt EventBridgeRole.Arn
58+
EventBridgeConfig:
59+
EventBusArn: !GetAtt 'EventBus.Arn'
60+
61+
AppSyncSayHelloResolver:
62+
DependsOn: ApiSchema
63+
Type: AWS::AppSync::Resolver
64+
Properties:
65+
ApiId: !GetAtt AppSyncApi.ApiId
66+
TypeName: Query
67+
FieldName: sayHello
68+
DataSourceName: !GetAtt AppSyncEventBusDataSource.Name
69+
Runtime:
70+
Name: APPSYNC_JS
71+
RuntimeVersion: 1.0.0
72+
Code: |
73+
import { util } from '@aws-appsync/utils';
74+
export function request(ctx) {
75+
return {
76+
"operation" : "PutEvents",
77+
"events" : [{
78+
"source": "com.mycompany.myapp",
79+
"detail": {
80+
"key1" : "value1",
81+
"key2" : "value2"
82+
},
83+
"resources": ["Resource1", "Resource2"],
84+
"detailType": "myDetailType"
85+
}]
86+
}
87+
}
88+
89+
export function response(ctx) {
90+
if(ctx.error)
91+
util.error(ctx.error.message, ctx.error.type, ctx.result)
92+
else
93+
return ctx.result
94+
}
95+
96+
Connector:
97+
Type: AWS::Serverless::Connector
98+
Properties:
99+
Source:
100+
Id: AppSyncEventBusDataSource
101+
Destination:
102+
Id: EventBus
103+
Permissions:
104+
- Write
105+
106+
ApiKey:
107+
Type: AWS::AppSync::ApiKey
108+
Properties:
109+
ApiId: !GetAtt AppSyncApi.ApiId
110+
111+
TriggerFunction:
112+
Type: AWS::Serverless::Function
113+
Properties:
114+
Role: !GetAtt EventBridgeRole.Arn
115+
Environment:
116+
Variables:
117+
API_KEY: !GetAtt ApiKey.ApiKey
118+
GRAPHQL_URL: !GetAtt AppSyncApi.GraphQLUrl
119+
EventBusName: !Ref EventBus
120+
Runtime: nodejs16.x
121+
Handler: index.handler
122+
InlineCode: |
123+
const https = require("https");
124+
125+
exports.handler = async () => {
126+
const queries = {
127+
sayHello: /* GraphQL */ `
128+
query {
129+
sayHello {
130+
Entries {
131+
ErrorCode
132+
EventId
133+
ErrorMessage
134+
}
135+
FailedEntry
136+
}
137+
}
138+
`,
139+
};
140+
141+
const fetch = async (url, options) =>
142+
new Promise((resolve, reject) => {
143+
const req = https.request(url, options, (res) => {
144+
const body = [];
145+
res.on("data", (chunk) => body.push(chunk));
146+
res.on("end", () => {
147+
const resString = Buffer.concat(body).toString();
148+
resolve(resString);
149+
});
150+
});
151+
req.on("error", (err) => {
152+
reject(err);
153+
});
154+
req.on("timeout", () => {
155+
req.destroy();
156+
reject(new Error("Request time out"));
157+
});
158+
req.write(options.body);
159+
req.end();
160+
});
161+
162+
const makeRequest = async (queryName) => {
163+
const options = {
164+
method: "POST",
165+
headers: {
166+
"x-api-key": process.env.API_KEY,
167+
},
168+
body: JSON.stringify({ query: queries[queryName] }),
169+
timeout: 600000, // ms
170+
};
171+
172+
const response = await fetch(process.env.GRAPHQL_URL, options);
173+
let body = JSON.parse(response);
174+
const data = body.data?.[queryName];
175+
176+
if (body.errors !== undefined) {
177+
throw JSON.stringify(body.errors);
178+
}
179+
180+
if (data.FailedEntry != null || data.ErrorCode != null ) {
181+
throw new Error(
182+
`${queryName} error: failed to send event to eventbus ${process.env.EventBusName}`);
183+
}
184+
185+
return body.data;
186+
};
187+
188+
await makeRequest("sayHello");
189+
};
190+
191+
Metadata:
192+
SamTransformTest: true

samtranslator/model/connector_profiles/profiles.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,23 @@
790790
}
791791
}
792792
}
793+
},
794+
"AWS::Events::EventBus": {
795+
"Type": "AWS_IAM_ROLE_MANAGED_POLICY",
796+
"Properties": {
797+
"SourcePolicy": true,
798+
"AccessCategories": {
799+
"Write": {
800+
"Statement": [
801+
{
802+
"Effect": "Allow",
803+
"Action": ["events:PutEvents"],
804+
"Resource": ["%{Destination.Arn}"]
805+
}
806+
]
807+
}
808+
}
809+
}
793810
}
794811
},
795812
"AWS::AppSync::GraphQLApi": {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
Resources:
2+
EventBus:
3+
Type: AWS::Events::EventBus
4+
Properties:
5+
Name: !Sub '${AWS::StackName}-EventBus'
6+
7+
EventBridgeRole:
8+
Type: AWS::IAM::Role
9+
Properties:
10+
RoleName: appsync-eventbridge-role
11+
AssumeRolePolicyDocument:
12+
Version: '2012-10-17'
13+
Statement:
14+
- Effect: Allow
15+
Action:
16+
- sts:AssumeRole
17+
Principal:
18+
Service:
19+
- appsync.amazonaws.com
20+
21+
AppSyncEventBusDataSource:
22+
Type: AWS::AppSync::DataSource
23+
Properties:
24+
ApiId: !GetAtt AppSyncApi.ApiId
25+
Name: MyDataSource
26+
Type: AMAZON_EVENTBRIDGE
27+
ServiceRoleArn: !GetAtt EventBridgeRole.Arn
28+
EventBridgeConfig:
29+
EventBusArn: !GetAtt 'EventBus.Arn'
30+
31+
AppSyncApi:
32+
Type: AWS::AppSync::GraphQLApi
33+
Properties:
34+
AuthenticationType: AWS_IAM
35+
Name: AppSyncApi
36+
37+
ApiSchema:
38+
Type: AWS::AppSync::GraphQLSchema
39+
Properties:
40+
ApiId: !GetAtt AppSyncApi.ApiId
41+
Definition: |
42+
type Note {
43+
NoteId: ID!
44+
title: String
45+
content: String
46+
}
47+
type Query {
48+
getNote(NoteId: ID!): Note
49+
}
50+
type Mutation {
51+
saveNote(NoteId: ID!, title: String!, content: String!): Note!
52+
}
53+
type Schema {
54+
query: Query
55+
mutation: Mutation
56+
}
57+
58+
Connector:
59+
Type: AWS::Serverless::Connector
60+
Properties:
61+
Source:
62+
Id: AppSyncEventBusDataSource
63+
Destination:
64+
Id: EventBus
65+
Permissions:
66+
- Write

0 commit comments

Comments
 (0)