From 8d4120ef8d35a008ea5fd2ed4ac6cdd074410fa8 Mon Sep 17 00:00:00 2001 From: Hubert Pompecki Date: Wed, 23 May 2018 15:52:40 +0100 Subject: [PATCH 1/5] Refactor request templates into a method --- lib/deploy/events/apiGateway/methods.js | 58 +++++++++++++------------ 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/deploy/events/apiGateway/methods.js b/lib/deploy/events/apiGateway/methods.js index 330176e3..fe8f965f 100644 --- a/lib/deploy/events/apiGateway/methods.js +++ b/lib/deploy/events/apiGateway/methods.js @@ -43,7 +43,6 @@ module.exports = { }, getMethodIntegration(stateMachineName, customName, http) { - const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName, customName); const apiToStepFunctionsIamRoleLogicalId = this.getApiToStepFunctionsIamRoleLogicalId(); const integration = { IntegrationHttpMethod: 'POST', @@ -67,32 +66,7 @@ module.exports = { ], }, PassthroughBehavior: 'NEVER', - RequestTemplates: { - 'application/json': { - 'Fn::Join': [ - '', [ - "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", - '{"input": "$body","name": "$context.requestId","stateMachineArn":"', - { - Ref: `${stateMachineLogicalId}`, - }, - '"}', - ], - ], - }, - 'application/x-www-form-urlencoded': { - 'Fn::Join': [ - '', [ - "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", - '{"input": "$body","name": "$context.requestId","stateMachineArn":"', - { - Ref: `${stateMachineLogicalId}`, - }, - '"}', - ], - ], - }, - }, + RequestTemplates: this.getIntegrationRequestTemplates(stateMachineName, customName, http) }; const integrationResponse = { @@ -134,6 +108,36 @@ module.exports = { }; }, + getIntegrationRequestTemplates(stateMachineName, customName, http) { + const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName, customName); + return { + 'application/json': { + 'Fn::Join': [ + '', [ + "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", + '{"input": "$body","name": "$context.requestId","stateMachineArn":"', + { + Ref: `${stateMachineLogicalId}`, + }, + '"}', + ], + ], + }, + 'application/x-www-form-urlencoded': { + 'Fn::Join': [ + '', [ + "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", + '{"input": "$body","name": "$context.requestId","stateMachineArn":"', + { + Ref: `${stateMachineLogicalId}`, + }, + '"}', + ], + ], + }, + } + }, + getMethodResponses(http) { const methodResponse = { Properties: { From 11c0c9870284c11657a4e96a80c5fcb358c557d3 Mon Sep 17 00:00:00 2001 From: Hubert Pompecki Date: Wed, 23 May 2018 16:47:32 +0100 Subject: [PATCH 2/5] Add custom templates support --- lib/deploy/events/apiGateway/methods.js | 47 ++++++------ lib/deploy/events/apiGateway/methods.test.js | 76 ++++++++++++++++++++ 2 files changed, 100 insertions(+), 23 deletions(-) diff --git a/lib/deploy/events/apiGateway/methods.js b/lib/deploy/events/apiGateway/methods.js index fe8f965f..c473dfce 100644 --- a/lib/deploy/events/apiGateway/methods.js +++ b/lib/deploy/events/apiGateway/methods.js @@ -109,32 +109,33 @@ module.exports = { }, getIntegrationRequestTemplates(stateMachineName, customName, http) { + const defaultRequestTemplates = this.getDefaultRequestTemplates(stateMachineName, customName); + return Object.assign( + defaultRequestTemplates, + _.get(http, ['request', 'template']) + ); + }, + + getDefaultRequestTemplates(stateMachineName, customName) { const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName, customName); return { - 'application/json': { - 'Fn::Join': [ - '', [ - "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", - '{"input": "$body","name": "$context.requestId","stateMachineArn":"', - { - Ref: `${stateMachineLogicalId}`, - }, - '"}', - ], - ], - }, - 'application/x-www-form-urlencoded': { - 'Fn::Join': [ - '', [ - "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", - '{"input": "$body","name": "$context.requestId","stateMachineArn":"', - { - Ref: `${stateMachineLogicalId}`, - }, - '"}', - ], + 'application/json': this.buildDefaultRequestTemplate(stateMachineLogicalId), + 'application/x-www-form-urlencoded': this.buildDefaultRequestTemplate(stateMachineLogicalId) + } + }, + + buildDefaultRequestTemplate(stateMachineLogicalId) { + return { + 'Fn::Join': [ + '', [ + "#set( $body = $util.escapeJavaScript($input.json('$')) ) \n\n", + '{"input": "$body","name": "$context.requestId","stateMachineArn":"', + { + Ref: `${stateMachineLogicalId}`, + }, + '"}', ], - }, + ], } }, diff --git a/lib/deploy/events/apiGateway/methods.test.js b/lib/deploy/events/apiGateway/methods.test.js index b8a5b805..31bba674 100644 --- a/lib/deploy/events/apiGateway/methods.test.js +++ b/lib/deploy/events/apiGateway/methods.test.js @@ -82,6 +82,7 @@ describe('#methods()', () => { .to.have.property('Integration'); }); + // Remove these 2 specs it('should set stateMachinelogical ID to RequestTemplates when customName is not set', () => { expect(serverlessStepFunctions.getMethodIntegration('stateMachine').Properties .Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref) @@ -115,6 +116,81 @@ describe('#methods()', () => { }); }); + describe('#getIntegrationRequestTemplates()', () => { + it('should set stateMachinelogical ID in default templates when customName is not set', () => { + expect(serverlessStepFunctions.getIntegrationRequestTemplates('stateMachine') + ['application/json']['Fn::Join'][1][2].Ref) + .to.be.equal('StateMachineStepFunctionsStateMachine'); + }); + + it('should set custom stateMachinelogical ID in default templates when customName is set', + () => { + expect(serverlessStepFunctions.getIntegrationRequestTemplates('stateMachine', 'custom') + ['application/json']['Fn::Join'][1][2].Ref) + .to.be.equal('Custom'); + }); + + it('should return the default template for application/json when one is not given', () => { + const http_without_request_template = { + path: 'foo/bar1', + method: 'post', + request: { + template: { + 'application/x-www-form-urlencoded': 'custom template' + } + } + } + expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_without_request_template) + .Properties.Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref) + .to.be.equal('StateMachineStepFunctionsStateMachine'); + }); + + it('should return a custom template for application/json when one is given', () => { + const http_with_request_template = { + path: 'foo/bar1', + method: 'post', + request: { + template: { + 'application/json': 'custom template' + } + } + } + expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_with_request_template) + .Properties.Integration.RequestTemplates['application/json']) + .to.be.equal('custom template'); + }); + + it('should return the default template for application/x-www-form-urlencoded when one is not given', () => { + const http_without_request_template = { + path: 'foo/bar1', + method: 'post', + request: { + template: { + 'application/json': 'custom template' + } + } + } + expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_without_request_template) + .Properties.Integration.RequestTemplates['application/x-www-form-urlencoded']['Fn::Join'][1][2].Ref) + .to.be.equal('StateMachineStepFunctionsStateMachine'); + }); + + it('should return a custom template for application/x-www-form-urlencoded when one is given', () => { + const http_with_request_template = { + path: 'foo/bar1', + method: 'post', + request: { + template: { + 'application/x-www-form-urlencoded': 'custom template' + } + } + } + expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_with_request_template) + .Properties.Integration.RequestTemplates['application/x-www-form-urlencoded']) + .to.be.equal('custom template'); + }); + }); + describe('#getMethodResponses()', () => { it('should return a corresponding methodResponses resource', () => { expect(serverlessStepFunctions.getMethodResponses().Properties) From 1256ab431c2d21f29f2613c859b1381bc2f3331d Mon Sep 17 00:00:00 2001 From: Hubert Pompecki Date: Fri, 25 May 2018 11:39:59 +0100 Subject: [PATCH 3/5] Update Readme --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index 297c8ffb..2ea7d8dd 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,32 @@ stepFunctions: 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. +#### Customizing request body mapping templates + +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`: + +```yml +stepFunctions: + stateMachines: + hello: + events: + - http: + path: posts/create + method: POST + request: + template: + application/json: | + #set( $body = $util.escapeJavaScript($input.json('$')) ) + #set( $name = $util.escapeJavaScript($input.json('$.data.attributes.order_id')) ) + { + "input": "$body", + "name": "$name", + "stateMachineArn":"arn:aws:states:#{AWS::Region}:#{AWS::AccountId}:stateMachine:processOrderFlow-${opt:stage}" + } + name: processOrderFlow-${opt:stage} + definition: +``` + #### Send request to an API You can input an value as json in request body, the value is passed as the input value of your statemachine From f272ddf6bf4e67596b3cb914abe0066677e94bba Mon Sep 17 00:00:00 2001 From: Hubert Pompecki Date: Fri, 25 May 2018 11:45:43 +0100 Subject: [PATCH 4/5] Clean up --- lib/deploy/events/apiGateway/methods.js | 2 +- lib/deploy/events/apiGateway/methods.test.js | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/deploy/events/apiGateway/methods.js b/lib/deploy/events/apiGateway/methods.js index c473dfce..f2f349c1 100644 --- a/lib/deploy/events/apiGateway/methods.js +++ b/lib/deploy/events/apiGateway/methods.js @@ -113,7 +113,7 @@ module.exports = { return Object.assign( defaultRequestTemplates, _.get(http, ['request', 'template']) - ); + ); }, getDefaultRequestTemplates(stateMachineName, customName) { diff --git a/lib/deploy/events/apiGateway/methods.test.js b/lib/deploy/events/apiGateway/methods.test.js index 31bba674..4bfc5797 100644 --- a/lib/deploy/events/apiGateway/methods.test.js +++ b/lib/deploy/events/apiGateway/methods.test.js @@ -82,20 +82,6 @@ describe('#methods()', () => { .to.have.property('Integration'); }); - // Remove these 2 specs - it('should set stateMachinelogical ID to RequestTemplates when customName is not set', () => { - expect(serverlessStepFunctions.getMethodIntegration('stateMachine').Properties - .Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref) - .to.be.equal('StateMachineStepFunctionsStateMachine'); - }); - - it('should set custom stateMachinelogical ID to RequestTemplates when customName is set', - () => { - expect(serverlessStepFunctions.getMethodIntegration('stateMachine', 'custom').Properties - .Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref) - .to.be.equal('Custom'); - }); - it('should set Access-Control-Allow-Origin header when cors is true', () => { expect(serverlessStepFunctions.getMethodIntegration('stateMachine', 'custom', { From 769300bf2a9650b8c378e57ed1d928e0f5cba438 Mon Sep 17 00:00:00 2001 From: Hubert Pompecki Date: Fri, 25 May 2018 13:40:41 +0100 Subject: [PATCH 5/5] Fix linting issues --- lib/deploy/events/apiGateway/methods.js | 8 +- lib/deploy/events/apiGateway/methods.test.js | 80 +++++++++++--------- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/lib/deploy/events/apiGateway/methods.js b/lib/deploy/events/apiGateway/methods.js index f2f349c1..8c761b45 100644 --- a/lib/deploy/events/apiGateway/methods.js +++ b/lib/deploy/events/apiGateway/methods.js @@ -66,7 +66,7 @@ module.exports = { ], }, PassthroughBehavior: 'NEVER', - RequestTemplates: this.getIntegrationRequestTemplates(stateMachineName, customName, http) + RequestTemplates: this.getIntegrationRequestTemplates(stateMachineName, customName, http), }; const integrationResponse = { @@ -120,8 +120,8 @@ module.exports = { const stateMachineLogicalId = this.getStateMachineLogicalId(stateMachineName, customName); return { 'application/json': this.buildDefaultRequestTemplate(stateMachineLogicalId), - 'application/x-www-form-urlencoded': this.buildDefaultRequestTemplate(stateMachineLogicalId) - } + 'application/x-www-form-urlencoded': this.buildDefaultRequestTemplate(stateMachineLogicalId), + }; }, buildDefaultRequestTemplate(stateMachineLogicalId) { @@ -136,7 +136,7 @@ module.exports = { '"}', ], ], - } + }; }, getMethodResponses(http) { diff --git a/lib/deploy/events/apiGateway/methods.test.js b/lib/deploy/events/apiGateway/methods.test.js index 4bfc5797..8170afab 100644 --- a/lib/deploy/events/apiGateway/methods.test.js +++ b/lib/deploy/events/apiGateway/methods.test.js @@ -104,75 +104,87 @@ describe('#methods()', () => { describe('#getIntegrationRequestTemplates()', () => { it('should set stateMachinelogical ID in default templates when customName is not set', () => { - expect(serverlessStepFunctions.getIntegrationRequestTemplates('stateMachine') - ['application/json']['Fn::Join'][1][2].Ref) + const requestTemplates = serverlessStepFunctions + .getIntegrationRequestTemplates('stateMachine'); + expect(requestTemplates['application/json']['Fn::Join'][1][2].Ref) .to.be.equal('StateMachineStepFunctionsStateMachine'); }); it('should set custom stateMachinelogical ID in default templates when customName is set', () => { - expect(serverlessStepFunctions.getIntegrationRequestTemplates('stateMachine', 'custom') - ['application/json']['Fn::Join'][1][2].Ref) + const requestTemplates = serverlessStepFunctions + .getIntegrationRequestTemplates('stateMachine', 'custom'); + expect(requestTemplates['application/json']['Fn::Join'][1][2].Ref) .to.be.equal('Custom'); }); it('should return the default template for application/json when one is not given', () => { - const http_without_request_template = { + const httpWithoutRequestTemplate = { path: 'foo/bar1', method: 'post', request: { template: { - 'application/x-www-form-urlencoded': 'custom template' - } - } - } - expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_without_request_template) - .Properties.Integration.RequestTemplates['application/json']['Fn::Join'][1][2].Ref) + 'application/x-www-form-urlencoded': 'custom template', + }, + }, + }; + const requestTemplates = serverlessStepFunctions + .getMethodIntegration('stateMachine', undefined, httpWithoutRequestTemplate) + .Properties.Integration.RequestTemplates; + expect(requestTemplates['application/json']['Fn::Join'][1][2].Ref) .to.be.equal('StateMachineStepFunctionsStateMachine'); }); it('should return a custom template for application/json when one is given', () => { - const http_with_request_template = { + const httpWithRequestTemplate = { path: 'foo/bar1', method: 'post', request: { template: { - 'application/json': 'custom template' - } - } - } - expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_with_request_template) - .Properties.Integration.RequestTemplates['application/json']) + 'application/json': 'custom template', + }, + }, + }; + const requestTemplates = serverlessStepFunctions + .getMethodIntegration('stateMachine', undefined, httpWithRequestTemplate) + .Properties.Integration.RequestTemplates; + expect(requestTemplates['application/json']) .to.be.equal('custom template'); }); - it('should return the default template for application/x-www-form-urlencoded when one is not given', () => { - const http_without_request_template = { + it('should return the default for application/x-www-form-urlencoded when one is not given', + () => { + const httpWithoutRequestTemplate = { path: 'foo/bar1', method: 'post', request: { template: { - 'application/json': 'custom template' - } - } - } - expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_without_request_template) - .Properties.Integration.RequestTemplates['application/x-www-form-urlencoded']['Fn::Join'][1][2].Ref) + 'application/json': 'custom template', + }, + }, + }; + const requestTemplates = serverlessStepFunctions + .getMethodIntegration('stateMachine', undefined, httpWithoutRequestTemplate) + .Properties.Integration.RequestTemplates; + expect(requestTemplates['application/x-www-form-urlencoded']['Fn::Join'][1][2].Ref) .to.be.equal('StateMachineStepFunctionsStateMachine'); }); - it('should return a custom template for application/x-www-form-urlencoded when one is given', () => { - const http_with_request_template = { + it('should return a custom template for application/x-www-form-urlencoded when one is given', + () => { + const httpWithRequestTemplate = { path: 'foo/bar1', method: 'post', request: { template: { - 'application/x-www-form-urlencoded': 'custom template' - } - } - } - expect(serverlessStepFunctions.getMethodIntegration('stateMachine', undefined, http_with_request_template) - .Properties.Integration.RequestTemplates['application/x-www-form-urlencoded']) + 'application/x-www-form-urlencoded': 'custom template', + }, + }, + }; + const requestTemplates = serverlessStepFunctions + .getMethodIntegration('stateMachine', undefined, httpWithRequestTemplate) + .Properties.Integration.RequestTemplates; + expect(requestTemplates['application/x-www-form-urlencoded']) .to.be.equal('custom template'); }); });