Skip to content

Commit 6b97aad

Browse files
committed
feat: allow passing additional request parameters for sqs
1 parent 89f5c50 commit 6b97aad

File tree

5 files changed

+194
-4
lines changed

5 files changed

+194
-4
lines changed

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,27 @@ custom:
214214
```
215215

216216
Source: [How to connect SNS to Kinesis for cross-account delivery via API Gateway](https://theburningmonk.com/2019/07/how-to-connect-sns-to-kinesis-for-cross-account-delivery-via-api-gateway/)
217+
218+
### SQS
219+
220+
#### Customizing request parameters
221+
222+
If you'd like to pass additional data to the integration request, you can do so by including your custom [API Gateway request parameters](https://docs.aws.amazon.com/apigateway/latest/developerguide/request-response-data-mappings.html) in `serverless.yml` like so:
223+
224+
```yml
225+
custom:
226+
apiGatewayServiceProxies:
227+
- sqs:
228+
path: /queue
229+
method: post
230+
queueName: !GetAtt MyQueue.QueueName
231+
cors: true
232+
233+
requestParameters:
234+
'integration.request.querystring.MessageAttribute.1.Name': "'cognitoIdentityId'"
235+
'integration.request.querystring.MessageAttribute.1.Value.StringValue': 'context.identity.cognitoIdentityId'
236+
'integration.request.querystring.MessageAttribute.1.Value.DataType': "'String'"
237+
'integration.request.querystring.MessageAttribute.2.Name': "'cognitoAuthenticationProvider'"
238+
'integration.request.querystring.MessageAttribute.2.Value.StringValue': 'context.identity.cognitoAuthenticationProvider'
239+
'integration.request.querystring.Me]
240+
```

lib/apiGateway/validate.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ module.exports = {
1616
http.method = await this.getProxyMethod(serviceProxy[serviceName], serviceName)
1717
http.auth = await this.getAuth(serviceProxy[serviceName], serviceName)
1818

19+
await this.validateRequestParameters(serviceProxy[serviceName], serviceName)
20+
1921
if (serviceProxy[serviceName].cors) {
2022
http.cors = await this.getCors(serviceProxy[serviceName])
2123

@@ -210,5 +212,28 @@ module.exports = {
210212
}
211213

212214
return auth
215+
},
216+
217+
async validateRequestParameters(proxy, serviceName) {
218+
if (!_.isUndefined(proxy.requestParameters)) {
219+
if (serviceName !== 'sqs') {
220+
return BbPromise.reject(
221+
new this.serverless.classes.Error(
222+
'requestParameters property is only valid for "sqs" service proxy'
223+
)
224+
)
225+
}
226+
227+
if (
228+
!_.isPlainObject(proxy.requestParameters) ||
229+
_.some(_.values(proxy.requestParameters), (v) => !_.isString(v))
230+
) {
231+
return BbPromise.reject(
232+
new this.serverless.classes.Error(
233+
'requestParameters property must be a string to string mapping'
234+
)
235+
)
236+
}
237+
}
213238
}
214239
}

lib/apiGateway/validate.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,4 +532,56 @@ describe('#validateServiceProxies()', () => {
532532
}
533533
)
534534
})
535+
536+
it('should validate requestParameters only used for sqs', async () => {
537+
serverlessApigatewayServiceProxy.serverless.service.custom = {
538+
apiGatewayServiceProxies: [
539+
{
540+
kinesis: {
541+
path: '/kinesis',
542+
method: 'post',
543+
requestParameters: { key: 'value' }
544+
}
545+
}
546+
]
547+
}
548+
549+
await expect(serverlessApigatewayServiceProxy.validateServiceProxies()).to.be.rejectedWith(
550+
'requestParameters property is only valid for "sqs" service proxy'
551+
)
552+
})
553+
554+
it('should validate requestParameters is a string to string mapping', async () => {
555+
serverlessApigatewayServiceProxy.serverless.service.custom = {
556+
apiGatewayServiceProxies: [
557+
{
558+
sqs: {
559+
path: '/sqs',
560+
method: 'post',
561+
requestParameters: { key1: 'value', key2: [] }
562+
}
563+
}
564+
]
565+
}
566+
567+
await expect(serverlessApigatewayServiceProxy.validateServiceProxies()).to.be.rejectedWith(
568+
'requestParameters property must be a string to string mapping'
569+
)
570+
})
571+
572+
it('should allow valid requestParameters property', async () => {
573+
serverlessApigatewayServiceProxy.serverless.service.custom = {
574+
apiGatewayServiceProxies: [
575+
{
576+
sqs: {
577+
path: '/sqs',
578+
method: 'post',
579+
requestParameters: { key1: 'value', key2: 'value2' }
580+
}
581+
}
582+
]
583+
}
584+
585+
await expect(serverlessApigatewayServiceProxy.validateServiceProxies()).to.be.fulfilled
586+
})
535587
})

lib/package/sqs/compileMethodsToSqs.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,13 @@ module.exports = {
7474
]
7575
]
7676
},
77-
RequestParameters: {
78-
'integration.request.querystring.Action': "'SendMessage'",
79-
'integration.request.querystring.MessageBody': 'method.request.body'
80-
},
77+
RequestParameters: _.merge(
78+
{
79+
'integration.request.querystring.Action': "'SendMessage'",
80+
'integration.request.querystring.MessageBody': 'method.request.body'
81+
},
82+
http.requestParameters
83+
),
8184
RequestTemplates: { 'application/json': '{statusCode:200}' }
8285
}
8386

lib/package/sqs/compileMethodsToSqs.test.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,4 +380,90 @@ describe('#compileIamRoleToSqs()', () => {
380380
}
381381
})
382382
})
383+
384+
it('should add additional requestParameters', async () => {
385+
serverlessApigatewayServiceProxy.validated = {
386+
events: [
387+
{
388+
serviceName: 'sqs',
389+
http: {
390+
queueName: 'myQueue',
391+
path: 'sqs',
392+
method: 'post',
393+
auth: {
394+
authorizationType: 'NONE'
395+
},
396+
requestParameters: { key1: 'value1', key2: 'value2' }
397+
}
398+
}
399+
]
400+
}
401+
serverlessApigatewayServiceProxy.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi'
402+
serverlessApigatewayServiceProxy.apiGatewayResources = {
403+
sqs: {
404+
name: 'sqs',
405+
resourceLogicalId: 'ApiGatewayResourceSqs'
406+
}
407+
}
408+
409+
await expect(serverlessApigatewayServiceProxy.compileMethodsToSqs()).to.be.fulfilled
410+
expect(serverless.service.provider.compiledCloudFormationTemplate.Resources).to.deep.equal({
411+
ApiGatewayMethodsqsPost: {
412+
Type: 'AWS::ApiGateway::Method',
413+
Properties: {
414+
HttpMethod: 'POST',
415+
RequestParameters: {},
416+
AuthorizationType: 'NONE',
417+
AuthorizationScopes: undefined,
418+
AuthorizerId: undefined,
419+
ApiKeyRequired: false,
420+
ResourceId: { Ref: 'ApiGatewayResourceSqs' },
421+
RestApiId: { Ref: 'ApiGatewayRestApi' },
422+
Integration: {
423+
IntegrationHttpMethod: 'POST',
424+
Type: 'AWS',
425+
Credentials: { 'Fn::GetAtt': ['ApigatewayToSqsRole', 'Arn'] },
426+
Uri: {
427+
'Fn::Join': [
428+
'',
429+
[
430+
'arn:aws:apigateway:',
431+
{ Ref: 'AWS::Region' },
432+
':sqs:path//',
433+
{ Ref: 'AWS::AccountId' },
434+
'/',
435+
'"myQueue"'
436+
]
437+
]
438+
},
439+
RequestParameters: {
440+
'integration.request.querystring.Action': "'SendMessage'",
441+
'integration.request.querystring.MessageBody': 'method.request.body',
442+
key1: 'value1',
443+
key2: 'value2'
444+
},
445+
RequestTemplates: { 'application/json': '{statusCode:200}' },
446+
IntegrationResponses: [
447+
{
448+
StatusCode: 200,
449+
SelectionPattern: 200,
450+
ResponseParameters: {},
451+
ResponseTemplates: {}
452+
},
453+
{
454+
StatusCode: 400,
455+
SelectionPattern: 400,
456+
ResponseParameters: {},
457+
ResponseTemplates: {}
458+
}
459+
]
460+
},
461+
MethodResponses: [
462+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 200 },
463+
{ ResponseParameters: {}, ResponseModels: {}, StatusCode: 400 }
464+
]
465+
}
466+
}
467+
})
468+
})
383469
})

0 commit comments

Comments
 (0)