Skip to content

Commit d053c93

Browse files
committed
feat(sqs): pass querystring request params into default request body
1 parent a9ad9f4 commit d053c93

File tree

3 files changed

+239
-5
lines changed

3 files changed

+239
-5
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ custom:
157157
'integration.request.querystring.MessageAttribute.2.Value.DataType': "'String'"
158158
```
159159

160+
The preferred way to pass `MessageAttribute` parameters is via a request body mapping template. Any `requestParameters` keys that begin with `integration.request.querystring.` will be automatically placed in the request body to maintain backward compatibility with existing implementations.
161+
160162
#### Customizing request body mapping templates
161163

162164
See the [SQS section](#sqs-1) under [Customizing request body mapping templates](#customizing-request-body-mapping-templates)

lib/package/sqs/compileMethodsToSqs.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ module.exports = {
4848
'Fn::GetAtt': ['ApigatewayToSqsRole', 'Arn']
4949
}
5050

51+
const isQuerystring = (_value, parameter) =>
52+
parameter.trim().startsWith('integration.request.querystring.')
53+
54+
const requestParametersQuerystrings = _.pickBy(http.requestParameters, isQuerystring)
55+
const requestParametersOthers = _.omitBy(http.requestParameters, isQuerystring)
56+
5157
const integration = {
5258
IntegrationHttpMethod: 'POST',
5359
Type: 'AWS',
@@ -63,9 +69,9 @@ module.exports = {
6369
{
6470
'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'"
6571
},
66-
http.requestParameters
72+
requestParametersOthers
6773
),
68-
RequestTemplates: this.getSqsIntegrationRequestTemplates(http)
74+
RequestTemplates: this.getSqsIntegrationRequestTemplates(http, requestParametersQuerystrings)
6975
}
7076

7177
let integrationResponse
@@ -140,9 +146,29 @@ module.exports = {
140146
}
141147
},
142148

143-
getSqsIntegrationRequestTemplates(http) {
144-
const defaultRequestTemplates = this.getDefaultSqsRequestTemplates()
145-
return Object.assign(defaultRequestTemplates, _.get(http, ['request', 'template']))
149+
getSqsIntegrationRequestTemplates(http, requestParametersQuerystrings) {
150+
const defaultRequestTemplates = this.getDefaultSqsRequestTemplates(http)
151+
const customRequestTemplates = _.get(http, ['request', 'template'])
152+
153+
if (_.isEmpty(customRequestTemplates) && !_.isEmpty(requestParametersQuerystrings)) {
154+
requestParametersQuerystrings = _.map(requestParametersQuerystrings, (value, parameter) => {
155+
return [
156+
parameter.trim().replace('integration.request.querystring.', ''),
157+
value
158+
.trim()
159+
.replace(/^context\.(.+)$/, '$$util.urlEncode($$context.$1)')
160+
.replace(/(^')|('$)/g, '')
161+
].join('=')
162+
})
163+
164+
return {
165+
'application/json': `${
166+
defaultRequestTemplates['application/json']
167+
}&${requestParametersQuerystrings.join('&')}`
168+
}
169+
}
170+
171+
return Object.assign(defaultRequestTemplates, customRequestTemplates)
146172
},
147173

148174
getDefaultSqsRequestTemplates() {

lib/package/sqs/compileMethodsToSqs.test.js

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,212 @@ describe('#compileMethodsToSqs()', () => {
714714
})
715715
})
716716

717+
it('should return a custom request template for application/json when one is given and not include custom request querystring parameters if provided', () => {
718+
serverlessApigatewayServiceProxy.validated = {
719+
events: [
720+
{
721+
serviceName: 'sqs',
722+
http: {
723+
queueName: 'myQueue',
724+
path: 'sqs',
725+
method: 'post',
726+
auth: {
727+
authorizationType: 'NONE'
728+
},
729+
requestParameters: {
730+
'integration.request.header.x-my-custom-header': "'foobar'",
731+
'integration.request.querystring.MessageAttribute.1.Name': "'cognitoIdentityId'",
732+
'integration.request.querystring.MessageAttribute.1.Value.StringValue':
733+
'context.identity.cognitoIdentityId',
734+
'integration.request.querystring.MessageAttribute.1.Value.DataType': "'String'",
735+
'integration.request.querystring.MessageAttribute.2.Name':
736+
"'cognitoAuthenticationProvider'",
737+
'integration.request.querystring.MessageAttribute.2.Value.StringValue':
738+
'context.identity.cognitoAuthenticationProvider',
739+
'integration.request.querystring.MessageAttribute.2.Value.DataType': "'String'"
740+
},
741+
request: {
742+
template: {
743+
'application/json': '##This template is just a comment'
744+
}
745+
}
746+
}
747+
}
748+
]
749+
}
750+
serverlessApigatewayServiceProxy.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi'
751+
serverlessApigatewayServiceProxy.apiGatewayResources = {
752+
sqs: {
753+
name: 'sqs',
754+
resourceLogicalId: 'ApiGatewayResourceSqs'
755+
}
756+
}
757+
758+
serverlessApigatewayServiceProxy.compileMethodsToSqs()
759+
760+
expect(serverless.service.provider.compiledCloudFormationTemplate.Resources).to.deep.equal({
761+
ApiGatewayMethodsqsPost: {
762+
Type: 'AWS::ApiGateway::Method',
763+
Properties: {
764+
HttpMethod: 'POST',
765+
RequestParameters: {},
766+
AuthorizationType: 'NONE',
767+
AuthorizationScopes: undefined,
768+
AuthorizerId: undefined,
769+
ApiKeyRequired: false,
770+
ResourceId: { Ref: 'ApiGatewayResourceSqs' },
771+
RestApiId: { Ref: 'ApiGatewayRestApi' },
772+
Integration: {
773+
IntegrationHttpMethod: 'POST',
774+
Type: 'AWS',
775+
Credentials: { 'Fn::GetAtt': ['ApigatewayToSqsRole', 'Arn'] },
776+
Uri: {
777+
'Fn::Sub': [
778+
'arn:aws:apigateway:${AWS::Region}:sqs:path//${AWS::AccountId}/${queueName}',
779+
{
780+
queueName: 'myQueue'
781+
}
782+
]
783+
},
784+
PassthroughBehavior: 'NEVER',
785+
RequestParameters: {
786+
'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'",
787+
'integration.request.header.x-my-custom-header': "'foobar'"
788+
},
789+
RequestTemplates: { 'application/json': '##This template is just a comment' },
790+
IntegrationResponses: [
791+
{
792+
StatusCode: 200,
793+
SelectionPattern: 200,
794+
ResponseParameters: {},
795+
ResponseTemplates: {}
796+
},
797+
{
798+
StatusCode: 400,
799+
SelectionPattern: 400,
800+
ResponseParameters: {},
801+
ResponseTemplates: {}
802+
},
803+
{
804+
StatusCode: 500,
805+
SelectionPattern: 500,
806+
ResponseParameters: {},
807+
ResponseTemplates: {}
808+
}
809+
]
810+
},
811+
MethodResponses: [
812+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 200 },
813+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 400 },
814+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 500 }
815+
]
816+
}
817+
}
818+
})
819+
})
820+
821+
it('should return a custom request template for application/json when custom request querystring parameters are provided and no custom request template is provided', () => {
822+
serverlessApigatewayServiceProxy.validated = {
823+
events: [
824+
{
825+
serviceName: 'sqs',
826+
http: {
827+
queueName: 'myQueue',
828+
path: 'sqs',
829+
method: 'post',
830+
auth: {
831+
authorizationType: 'NONE'
832+
},
833+
requestParameters: {
834+
'integration.request.header.x-my-custom-header': "'foobar'",
835+
'integration.request.querystring.MessageAttribute.1.Name': "'cognitoIdentityId'",
836+
'integration.request.querystring.MessageAttribute.1.Value.StringValue':
837+
'context.identity.cognitoIdentityId',
838+
'integration.request.querystring.MessageAttribute.1.Value.DataType': "'String'",
839+
'integration.request.querystring.MessageAttribute.2.Name':
840+
"'cognitoAuthenticationProvider'",
841+
'integration.request.querystring.MessageAttribute.2.Value.StringValue':
842+
'context.identity.cognitoAuthenticationProvider',
843+
'integration.request.querystring.MessageAttribute.2.Value.DataType': "'String'"
844+
}
845+
}
846+
}
847+
]
848+
}
849+
serverlessApigatewayServiceProxy.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi'
850+
serverlessApigatewayServiceProxy.apiGatewayResources = {
851+
sqs: {
852+
name: 'sqs',
853+
resourceLogicalId: 'ApiGatewayResourceSqs'
854+
}
855+
}
856+
857+
serverlessApigatewayServiceProxy.compileMethodsToSqs()
858+
859+
expect(serverless.service.provider.compiledCloudFormationTemplate.Resources).to.deep.equal({
860+
ApiGatewayMethodsqsPost: {
861+
Type: 'AWS::ApiGateway::Method',
862+
Properties: {
863+
HttpMethod: 'POST',
864+
RequestParameters: {},
865+
AuthorizationType: 'NONE',
866+
AuthorizationScopes: undefined,
867+
AuthorizerId: undefined,
868+
ApiKeyRequired: false,
869+
ResourceId: { Ref: 'ApiGatewayResourceSqs' },
870+
RestApiId: { Ref: 'ApiGatewayRestApi' },
871+
Integration: {
872+
IntegrationHttpMethod: 'POST',
873+
Type: 'AWS',
874+
Credentials: { 'Fn::GetAtt': ['ApigatewayToSqsRole', 'Arn'] },
875+
Uri: {
876+
'Fn::Sub': [
877+
'arn:aws:apigateway:${AWS::Region}:sqs:path//${AWS::AccountId}/${queueName}',
878+
{
879+
queueName: 'myQueue'
880+
}
881+
]
882+
},
883+
PassthroughBehavior: 'NEVER',
884+
RequestParameters: {
885+
'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'",
886+
'integration.request.header.x-my-custom-header': "'foobar'"
887+
},
888+
RequestTemplates: {
889+
'application/json':
890+
'Action=SendMessage&MessageBody=$util.urlEncode($input.body)&MessageAttribute.1.Name=cognitoIdentityId&MessageAttribute.1.Value.StringValue=$util.urlEncode($context.identity.cognitoIdentityId)&MessageAttribute.1.Value.DataType=String&MessageAttribute.2.Name=cognitoAuthenticationProvider&MessageAttribute.2.Value.StringValue=$util.urlEncode($context.identity.cognitoAuthenticationProvider)&MessageAttribute.2.Value.DataType=String'
891+
},
892+
IntegrationResponses: [
893+
{
894+
StatusCode: 200,
895+
SelectionPattern: 200,
896+
ResponseParameters: {},
897+
ResponseTemplates: {}
898+
},
899+
{
900+
StatusCode: 400,
901+
SelectionPattern: 400,
902+
ResponseParameters: {},
903+
ResponseTemplates: {}
904+
},
905+
{
906+
StatusCode: 500,
907+
SelectionPattern: 500,
908+
ResponseParameters: {},
909+
ResponseTemplates: {}
910+
}
911+
]
912+
},
913+
MethodResponses: [
914+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 200 },
915+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 400 },
916+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 500 }
917+
]
918+
}
919+
}
920+
})
921+
})
922+
717923
it('should set Credentials to roleArn when a custom role is configured', () => {
718924
const http = {
719925
queueName: 'myQueue',

0 commit comments

Comments
 (0)