Skip to content

Commit 5c4c01e

Browse files
authored
Merge pull request #122 from hubertpompecki/custom_body_mapping_templates
Add support for custom body mapping templates
2 parents b0ec985 + 769300b commit 5c4c01e

File tree

3 files changed

+145
-40
lines changed

3 files changed

+145
-40
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,32 @@ stepFunctions:
186186

187187
Configuring the cors property sets Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Allow-Methods,Access-Control-Allow-Credentials headers in the CORS preflight response.
188188

189+
#### Customizing request body mapping templates
190+
191+
The plugin generates default body mapping templates for `application/json` and `application/x-www-form-urlencoded` content types. If you'd like to add more content types or customize the default ones, you can do so by including them in `serverless.yml`:
192+
193+
```yml
194+
stepFunctions:
195+
stateMachines:
196+
hello:
197+
events:
198+
- http:
199+
path: posts/create
200+
method: POST
201+
request:
202+
template:
203+
application/json: |
204+
#set( $body = $util.escapeJavaScript($input.json('$')) )
205+
#set( $name = $util.escapeJavaScript($input.json('$.data.attributes.order_id')) )
206+
{
207+
"input": "$body",
208+
"name": "$name",
209+
"stateMachineArn":"arn:aws:states:#{AWS::Region}:#{AWS::AccountId}:stateMachine:processOrderFlow-${opt:stage}"
210+
}
211+
name: processOrderFlow-${opt:stage}
212+
definition:
213+
```
214+
189215
#### Send request to an API
190216
You can input an value as json in request body, the value is passed as the input value of your statemachine
191217

lib/deploy/events/apiGateway/methods.js

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ module.exports = {
4343
},
4444

4545
getMethodIntegration(stateMachineName, customName, http) {
46-
const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName, customName);
4746
const apiToStepFunctionsIamRoleLogicalId = this.getApiToStepFunctionsIamRoleLogicalId();
4847
const integration = {
4948
IntegrationHttpMethod: 'POST',
@@ -67,32 +66,7 @@ module.exports = {
6766
],
6867
},
6968
PassthroughBehavior: 'NEVER',
70-
RequestTemplates: {
71-
'application/json': {
72-
'Fn::Join': [
73-
'', [
74-
"#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n",
75-
'{"input": "$body","name": "$context.requestId","stateMachineArn":"',
76-
{
77-
Ref: `${stateMachineLogicalId}`,
78-
},
79-
'"}',
80-
],
81-
],
82-
},
83-
'application/x-www-form-urlencoded': {
84-
'Fn::Join': [
85-
'', [
86-
"#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n",
87-
'{"input": "$body","name": "$context.requestId","stateMachineArn":"',
88-
{
89-
Ref: `${stateMachineLogicalId}`,
90-
},
91-
'"}',
92-
],
93-
],
94-
},
95-
},
69+
RequestTemplates: this.getIntegrationRequestTemplates(stateMachineName, customName, http),
9670
};
9771

9872
const integrationResponse = {
@@ -134,6 +108,37 @@ module.exports = {
134108
};
135109
},
136110

111+
getIntegrationRequestTemplates(stateMachineName, customName, http) {
112+
const defaultRequestTemplates = this.getDefaultRequestTemplates(stateMachineName, customName);
113+
return Object.assign(
114+
defaultRequestTemplates,
115+
_.get(http, ['request', 'template'])
116+
);
117+
},
118+
119+
getDefaultRequestTemplates(stateMachineName, customName) {
120+
const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName, customName);
121+
return {
122+
'application/json': this.buildDefaultRequestTemplate(stateMachineLogicalId),
123+
'application/x-www-form-urlencoded': this.buildDefaultRequestTemplate(stateMachineLogicalId),
124+
};
125+
},
126+
127+
buildDefaultRequestTemplate(stateMachineLogicalId) {
128+
return {
129+
'Fn::Join': [
130+
'', [
131+
"#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n",
132+
'{"input": "$body","name": "$context.requestId","stateMachineArn":"',
133+
{
134+
Ref: `${stateMachineLogicalId}`,
135+
},
136+
'"}',
137+
],
138+
],
139+
};
140+
},
141+
137142
getMethodResponses(http) {
138143
const methodResponse = {
139144
Properties: {

lib/deploy/events/apiGateway/methods.test.js

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,6 @@ describe('#methods()', () => {
8282
.to.have.property('Integration');
8383
});
8484

85-
it('should set stateMachinelogical ID to RequestTemplates when customName is not set', () => {
86-
expect(serverlessStepFunctions.getMethodIntegration('stateMachine').Properties
87-
.Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref)
88-
.to.be.equal('StateMachineStepFunctionsStateMachine');
89-
});
90-
91-
it('should set custom stateMachinelogical ID to RequestTemplates when customName is set',
92-
() => {
93-
expect(serverlessStepFunctions.getMethodIntegration('stateMachine', 'custom').Properties
94-
.Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref)
95-
.to.be.equal('Custom');
96-
});
97-
9885
it('should set Access-Control-Allow-Origin header when cors is true',
9986
() => {
10087
expect(serverlessStepFunctions.getMethodIntegration('stateMachine', 'custom', {
@@ -115,6 +102,93 @@ describe('#methods()', () => {
115102
});
116103
});
117104

105+
describe('#getIntegrationRequestTemplates()', () => {
106+
it('should set stateMachinelogical ID in default templates when customName is not set', () => {
107+
const requestTemplates = serverlessStepFunctions
108+
.getIntegrationRequestTemplates('stateMachine');
109+
expect(requestTemplates['application/json']['Fn::Join'][1][2].Ref)
110+
.to.be.equal('StateMachineStepFunctionsStateMachine');
111+
});
112+
113+
it('should set custom stateMachinelogical ID in default templates when customName is set',
114+
() => {
115+
const requestTemplates = serverlessStepFunctions
116+
.getIntegrationRequestTemplates('stateMachine', 'custom');
117+
expect(requestTemplates['application/json']['Fn::Join'][1][2].Ref)
118+
.to.be.equal('Custom');
119+
});
120+
121+
it('should return the default template for application/json when one is not given', () => {
122+
const httpWithoutRequestTemplate = {
123+
path: 'foo/bar1',
124+
method: 'post',
125+
request: {
126+
template: {
127+
'application/x-www-form-urlencoded': 'custom template',
128+
},
129+
},
130+
};
131+
const requestTemplates = serverlessStepFunctions
132+
.getMethodIntegration('stateMachine', undefined, httpWithoutRequestTemplate)
133+
.Properties.Integration.RequestTemplates;
134+
expect(requestTemplates['application/json']['Fn::Join'][1][2].Ref)
135+
.to.be.equal('StateMachineStepFunctionsStateMachine');
136+
});
137+
138+
it('should return a custom template for application/json when one is given', () => {
139+
const httpWithRequestTemplate = {
140+
path: 'foo/bar1',
141+
method: 'post',
142+
request: {
143+
template: {
144+
'application/json': 'custom template',
145+
},
146+
},
147+
};
148+
const requestTemplates = serverlessStepFunctions
149+
.getMethodIntegration('stateMachine', undefined, httpWithRequestTemplate)
150+
.Properties.Integration.RequestTemplates;
151+
expect(requestTemplates['application/json'])
152+
.to.be.equal('custom template');
153+
});
154+
155+
it('should return the default for application/x-www-form-urlencoded when one is not given',
156+
() => {
157+
const httpWithoutRequestTemplate = {
158+
path: 'foo/bar1',
159+
method: 'post',
160+
request: {
161+
template: {
162+
'application/json': 'custom template',
163+
},
164+
},
165+
};
166+
const requestTemplates = serverlessStepFunctions
167+
.getMethodIntegration('stateMachine', undefined, httpWithoutRequestTemplate)
168+
.Properties.Integration.RequestTemplates;
169+
expect(requestTemplates['application/x-www-form-urlencoded']['Fn::Join'][1][2].Ref)
170+
.to.be.equal('StateMachineStepFunctionsStateMachine');
171+
});
172+
173+
it('should return a custom template for application/x-www-form-urlencoded when one is given',
174+
() => {
175+
const httpWithRequestTemplate = {
176+
path: 'foo/bar1',
177+
method: 'post',
178+
request: {
179+
template: {
180+
'application/x-www-form-urlencoded': 'custom template',
181+
},
182+
},
183+
};
184+
const requestTemplates = serverlessStepFunctions
185+
.getMethodIntegration('stateMachine', undefined, httpWithRequestTemplate)
186+
.Properties.Integration.RequestTemplates;
187+
expect(requestTemplates['application/x-www-form-urlencoded'])
188+
.to.be.equal('custom template');
189+
});
190+
});
191+
118192
describe('#getMethodResponses()', () => {
119193
it('should return a corresponding methodResponses resource', () => {
120194
expect(serverlessStepFunctions.getMethodResponses().Properties)

0 commit comments

Comments
 (0)