Skip to content

Commit f3913cf

Browse files
committed
add API Gateway + Step Functions
1 parent f73109e commit f3913cf

File tree

6 files changed

+179
-5
lines changed

6 files changed

+179
-5
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"Type": "AWS::IAM::Role",
3+
"Properties": {
4+
"AssumeRolePolicyDocument": {
5+
"Version": "2012-10-17",
6+
"Statement": [
7+
{
8+
"Effect": "Allow",
9+
"Principal": {
10+
"Service": "apigateway.amazonaws.com"
11+
},
12+
"Action": "sts:AssumeRole"
13+
}
14+
]
15+
},
16+
"Policies": [
17+
{
18+
"PolicyName": "apigatewaytostepfunctions",
19+
"PolicyDocument": {
20+
"Version": "2012-10-17",
21+
"Statement": [
22+
{
23+
"Effect": "Allow",
24+
"Action": [
25+
"states:StartExecution"
26+
],
27+
"Resource": "*"
28+
}
29+
]
30+
}
31+
}
32+
]
33+
}
34+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const _ = require('lodash');
4+
const BbPromise = require('bluebird');
5+
6+
module.exports = {
7+
compileDeployment() {
8+
this.apiGatewayDeploymentLogicalId = this.provider.naming
9+
.generateApiGatewayDeploymentLogicalId();
10+
11+
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, {
12+
[this.apiGatewayDeploymentLogicalId]: {
13+
Type: 'AWS::ApiGateway::Deployment',
14+
Properties: {
15+
RestApiId: { Ref: this.apiGatewayRestApiLogicalId },
16+
StageName: this.options.stage,
17+
},
18+
DependsOn: this.apiGatewayMethodLogicalIds,
19+
},
20+
});
21+
22+
// create CLF Output for endpoint
23+
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Outputs, {
24+
ServiceEndpoint: {
25+
Description: 'URL of the service endpoint',
26+
Value: {
27+
'Fn::Join': ['',
28+
[
29+
'https://',
30+
{ Ref: this.apiGatewayRestApiLogicalId },
31+
`.execute-api.${this.options.region}.amazonaws.com/${this.options.stage}`,
32+
],
33+
],
34+
},
35+
},
36+
});
37+
return BbPromise.resolve();
38+
},
39+
};

lib/deploy/events/apiGateway/methods.js

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ module.exports = {
88
compileMethods() {
99
this.apiGatewayMethodLogicalIds = [];
1010

11+
if (this.isCoreHttpevents()) {
12+
_.forEach(this.serverless.service.functions, (functionObject) => {
13+
_.forEach(functionObject.events, (event) => {
14+
if (_.has(event, 'http')) {
15+
const methodLogicalId = this.provider.naming
16+
.getMethodLogicalId(this.getResourceName(event.http.path), event.http.method);
17+
this.apiGatewayMethodLogicalIds.push(methodLogicalId);
18+
}
19+
});
20+
});
21+
}
22+
1123
this.pluginhttpValidated.events.forEach((event) => {
1224
const resourceId = this.getResourceId(event.http.path);
1325
const resourceName = this.getResourceName(event.http.path);
@@ -18,6 +30,7 @@ module.exports = {
1830
Properties: {
1931
HttpMethod: event.http.method.toUpperCase(),
2032
RequestParameters: requestParameters,
33+
AuthorizationType: 'NONE',
2134
ResourceId: resourceId,
2235
RestApiId: { Ref: this.apiGatewayRestApiLogicalId },
2336
},
@@ -28,8 +41,8 @@ module.exports = {
2841
}
2942

3043
_.merge(template,
31-
this.getMethodIntegration(event.http, event.stateMachineName)
32-
// this.getMethodResponses(event.http)
44+
this.getMethodIntegration(event.stateMachineName),
45+
this.getMethodResponses()
3346
);
3447

3548
const methodLogicalId = this.provider.naming
@@ -45,14 +58,15 @@ module.exports = {
4558
return BbPromise.resolve();
4659
},
4760

48-
getMethodIntegration(http, stateMachineName) {
61+
getMethodIntegration(stateMachineName) {
4962
const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName);
63+
const apiToStepFunctionsIamRoleLogicalId = this.getApiToStepFunctionsIamRoleLogicalId();
5064
const integration = {
5165
IntegrationHttpMethod: 'POST',
5266
Type: 'AWS',
5367
Credentials: {
5468
'Fn::GetAtt': [
55-
'APIAssumeRolePolicyDocument',
69+
`${apiToStepFunctionsIamRoleLogicalId}`,
5670
'Arn',
5771
],
5872
},
@@ -105,4 +119,23 @@ module.exports = {
105119
},
106120
};
107121
},
122+
123+
getMethodResponses() {
124+
return {
125+
Properties: {
126+
MethodResponses: [
127+
{
128+
ResponseParameters: {},
129+
ResponseModels: {},
130+
StatusCode: 200,
131+
},
132+
{
133+
ResponseParameters: {},
134+
ResponseModels: {},
135+
StatusCode: 400,
136+
},
137+
],
138+
},
139+
};
140+
},
108141
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
const _ = require('lodash');
3+
const BbPromise = require('bluebird');
4+
const path = require('path');
5+
6+
module.exports = {
7+
compileHttpIamRole() {
8+
const iamRoleApiGatewayToStepFunctionsTemplate =
9+
JSON.stringify(this.serverless.utils.readFileSync(
10+
path.join(__dirname,
11+
'apigateway-to-stepfunctions-assume-role.json'))
12+
);
13+
14+
const getApiToStepFunctionsIamRoleLogicalId = this.getApiToStepFunctionsIamRoleLogicalId();
15+
const newIamRoleStateMachineExecutionObject = {
16+
[getApiToStepFunctionsIamRoleLogicalId]: JSON.parse(iamRoleApiGatewayToStepFunctionsTemplate),
17+
};
18+
19+
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
20+
newIamRoleStateMachineExecutionObject);
21+
return BbPromise.resolve();
22+
},
23+
};

lib/index.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ const compileIamRole = require('./deploy/stepFunctions/compileIamRole');
77
const httpValidate = require('./deploy/events/apiGateway/validate');
88
const httpResources = require('./deploy/events/apiGateway/resources');
99
const httpMethods = require('./deploy/events/apiGateway/methods');
10+
const httpIamRole = require('./deploy/events/apiGateway/role');
11+
const httpDeployment = require('./deploy/events/apiGateway/deployment');
1012
const coreCompileRestApi =
1113
require('serverless/lib/plugins/aws/deploy/compile/events/apiGateway/lib/restApi');
14+
const coreInfo =
15+
require('serverless/lib/plugins/aws/info/getStackInfo');
1216
const yamlParser = require('./yamlParser');
1317
const naming = require('./naming');
1418
const _ = require('lodash');
19+
const chalk = require('chalk');
1520

1621
class ServerlessStepFunctions {
1722
constructor(serverless, options) {
@@ -38,9 +43,12 @@ class ServerlessStepFunctions {
3843
compileActivities,
3944
compileIamRole,
4045
coreCompileRestApi,
46+
coreInfo,
4147
httpValidate,
4248
httpResources,
4349
httpMethods,
50+
httpIamRole,
51+
httpDeployment,
4452
yamlParser,
4553
naming
4654
);
@@ -100,16 +108,49 @@ class ServerlessStepFunctions {
100108
return BbPromise.bind(this)
101109
.then(this.compileRestApi)
102110
.then(this.compileResources)
103-
.then(this.compileMethods);
111+
.then(this.compileMethods)
112+
.then(this.compileHttpIamRole)
113+
.then(this.compileDeployment);
104114
}
105115
return BbPromise.bind(this)
106116
.then(this.compileResources);
107117
},
118+
'after:deploy:deploy': () => BbPromise.bind(this)
119+
.then(this.getStackInfo)
120+
.then(this.display),
108121
};
109122
}
110123

111124
invoke() {
112125

113126
}
127+
128+
display() {
129+
let message = '';
130+
131+
const info = this.gatheredData.info;
132+
message += `${chalk.yellow.underline('Serverless StepFunctions OutPut')}\n`;
133+
message += `${chalk.yellow('endpoints:')}`;
134+
_.forEach(this.getAllStateMachines(), (stateMachineName) => {
135+
const stateMachineObj = this.getStateMachine(stateMachineName);
136+
stateMachineObj.events.forEach(event => {
137+
if (event.http) {
138+
let method;
139+
let path;
140+
141+
if (typeof event.http === 'object') {
142+
method = event.http.method.toUpperCase();
143+
path = event.http.path;
144+
} else {
145+
method = event.http.split(' ')[0].toUpperCase();
146+
path = event.http.split(' ')[1];
147+
}
148+
path = path !== '/' ? `/${path.split('/').filter(p => p !== '').join('/')}` : '';
149+
message += `\n ${method} - ${info.endpoint}${path}`;
150+
}
151+
});
152+
});
153+
this.serverless.cli.consoleLog(message);
154+
}
114155
}
115156
module.exports = ServerlessStepFunctions;

lib/naming.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ module.exports = {
3131
getApiGatewayName() {
3232
return `${this.provider.getStage()}-${this.provider.serverless.service.service}-stepfunctions`;
3333
},
34+
35+
getApiToStepFunctionsIamRoleLogicalId() {
36+
return 'ApigatewayToStepFunctionsRole';
37+
},
3438
};

0 commit comments

Comments
 (0)