Skip to content

Commit 715b02f

Browse files
authored
Merge pull request #178 from jlangsu/master
feat(dynamodb): add response template support for dynamodb
2 parents acb8ab1 + d282233 commit 715b02f

File tree

5 files changed

+162
-27
lines changed

5 files changed

+162
-27
lines changed

README.md

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This Serverless Framework plugin supports the AWS service proxy integration feat
2626
- [SNS](#sns)
2727
- [Customizing responses](#customizing-responses-2)
2828
- [DynamoDB](#dynamodb)
29+
- [Customizing responses](#customizing-responses-3)
2930
- [EventBridge](#eventbridge)
3031
- [Common API Gateway features](#common-api-gateway-features)
3132
- [Enabling CORS](#enabling-cors)
@@ -446,7 +447,7 @@ custom:
446447
template:
447448
# `success` is used when the integration response is 200
448449
success: |-
449-
{ "message: "accepted" }
450+
{ "message": "accepted" }
450451
# `clientError` is used when the integration response is 400
451452
clientError: |-
452453
{ "message": "there is an error in your request" }
@@ -568,6 +569,69 @@ curl -XPUT https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/dynamodb/<has
568569
-H 'Content-Type:application/json'
569570
```
570571

572+
#### Customizing responses
573+
574+
##### Simplified response template customization
575+
576+
You can get a simple customization of the responses by providing a template for the possible responses. The template returns the same kind of response for both `application/json` and `application/x-www-form-urlendcoded`.
577+
578+
```yml
579+
custom:
580+
apiGatewayServiceProxies:
581+
- dynamodb:
582+
path: /dynamodb
583+
method: get
584+
tableName: { Ref: 'YourTable' }
585+
hashKey:
586+
queryStringParam: id # use query string parameter
587+
attributeType: S
588+
rangeKey:
589+
queryStringParam: sort
590+
attributeType: S
591+
action: GetItem
592+
cors: true
593+
response:
594+
template:
595+
# `success` is used when the integration response is 200
596+
success: |-
597+
#set($item = $input.path('$.Item')){ "Item": $item }
598+
# `clientError` is used when the integration response is 400
599+
clientError: |-
600+
{ "message": "there is an error in your request" }
601+
# `serverError` is used when the integration response is 500
602+
serverError: |-
603+
{ "message": "there was an error handling your request" }
604+
```
605+
606+
##### Full response customization
607+
608+
If you want more control over the integration response, you can
609+
provide an array of objects for the `response` value:
610+
611+
```yml
612+
custom:
613+
apiGatewayServiceProxies:
614+
- dynamodb:
615+
path: /dynamodb
616+
method: get
617+
tableName: { Ref: 'YourTable' }
618+
hashKey:
619+
queryStringParam: id # use query string parameter
620+
attributeType: S
621+
rangeKey:
622+
queryStringParam: sort
623+
attributeType: S
624+
action: GetItem
625+
cors: true
626+
response:
627+
- statusCode: 200
628+
selectionPattern: '2\\d{2}'
629+
responseParameters: {}
630+
responseTemplates:
631+
application/json: |-
632+
#set($item = $input.path('$.Item')){ "Item": $item }
633+
634+
```
571635

572636
### EventBridge
573637

lib/apiGateway/schema.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,9 @@ const proxiesSchemas = {
300300
condition: Joi.string(),
301301
hashKey: dynamodbDefaultKeyScheme.required(),
302302
rangeKey: dynamodbDefaultKeyScheme,
303-
request
303+
requestParameters,
304+
request,
305+
response: extendedResponse
304306
})
305307
}),
306308
eventbridge: Joi.object({

lib/package/dynamodb/compileMethodsToDynamodb.js

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module.exports = {
1414
Type: 'AWS::ApiGateway::Method',
1515
Properties: {
1616
HttpMethod: event.http.method.toUpperCase(),
17-
RequestParameters: {},
17+
RequestParameters: event.http.acceptParameters || {},
1818
AuthorizationType: event.http.auth.authorizationType,
1919
AuthorizationScopes: event.http.auth.authorizationScopes,
2020
AuthorizerId: event.http.auth.authorizerId,
@@ -58,30 +58,68 @@ module.exports = {
5858
]
5959
},
6060
PassthroughBehavior: 'NEVER',
61+
RequestParameters: this.getDynamodbIntegrationRequestParameters(http),
6162
RequestTemplates: this.getDynamodbIntegrationRequestTemplates(http)
6263
}
6364

64-
const integrationResponse = {
65-
IntegrationResponses: [
66-
{
67-
StatusCode: 200,
68-
SelectionPattern: '2\\d{2}',
69-
ResponseParameters: {},
70-
ResponseTemplates: this.getDefaultDynamodbResponseTemplates(http)
71-
},
72-
{
73-
StatusCode: 400,
74-
SelectionPattern: '4\\d{2}',
75-
ResponseParameters: {},
76-
ResponseTemplates: {}
77-
},
78-
{
79-
StatusCode: 500,
80-
SelectionPattern: '5\\d{2}',
81-
ResponseParameters: {},
82-
ResponseTemplates: {}
83-
}
84-
]
65+
let integrationResponse
66+
67+
if (_.get(http.response, 'template.success')) {
68+
// support a simplified model
69+
integrationResponse = {
70+
IntegrationResponses: [
71+
{
72+
StatusCode: 200,
73+
SelectionPattern: 200,
74+
ResponseParameters: {},
75+
ResponseTemplates: this.getDynamodbResponseTemplates(http, 'success')
76+
},
77+
{
78+
StatusCode: 400,
79+
SelectionPattern: 400,
80+
ResponseParameters: {},
81+
ResponseTemplates: this.getDynamodbResponseTemplates(http, 'clientError')
82+
},
83+
{
84+
StatusCode: 500,
85+
SelectionPattern: 500,
86+
ResponseParameters: {},
87+
ResponseTemplates: this.getDynamodbResponseTemplates(http, 'serverError')
88+
}
89+
]
90+
}
91+
} else if (_.isArray(http.response)) {
92+
integrationResponse = {
93+
IntegrationResponses: http.response.map((i) => ({
94+
StatusCode: i.statusCode,
95+
SelectionPattern: i.selectionPattern || i.statusCode,
96+
ResponseParameters: i.responseParameters || {},
97+
ResponseTemplates: i.responseTemplates || {}
98+
}))
99+
}
100+
} else {
101+
integrationResponse = {
102+
IntegrationResponses: [
103+
{
104+
StatusCode: 200,
105+
SelectionPattern: '2\\d{2}',
106+
ResponseParameters: {},
107+
ResponseTemplates: this.getDefaultDynamodbResponseTemplates(http, 'success')
108+
},
109+
{
110+
StatusCode: 400,
111+
SelectionPattern: '4\\d{2}',
112+
ResponseParameters: {},
113+
ResponseTemplates: {}
114+
},
115+
{
116+
StatusCode: 500,
117+
SelectionPattern: '5\\d{2}',
118+
ResponseParameters: {},
119+
ResponseTemplates: {}
120+
}
121+
]
122+
}
85123
}
86124

87125
this.addCors(http, integrationResponse)
@@ -107,6 +145,15 @@ module.exports = {
107145
}
108146
},
109147

148+
getDynamodbIntegrationRequestParameters(http) {
149+
const defaultRequestParameters = this.buildDefaultDynamodbRequestParameters(http)
150+
return Object.assign(defaultRequestParameters, _.get(http, ['requestParameters']))
151+
},
152+
153+
buildDefaultDynamodbRequestParameters(http) {
154+
return _.merge({}, http.requestParameters)
155+
},
156+
110157
getDynamodbObjectHashkeyParameter(http) {
111158
if (http.hashKey.pathParam) {
112159
return {
@@ -143,6 +190,17 @@ module.exports = {
143190
}
144191
},
145192

193+
getDynamodbResponseTemplates(http, statusType) {
194+
const template = _.get(http, ['response', 'template', statusType])
195+
return Object.assign(
196+
{},
197+
template && {
198+
'application/json': template,
199+
'application/x-www-form-urlendcoded': template
200+
}
201+
)
202+
},
203+
146204
getDefaultDynamodbResponseTemplates(http) {
147205
if (http.action === 'GetItem') {
148206
return {

lib/package/dynamodb/compileMethodsToDynamodb.test.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,15 @@ describe('#compileMethodsToDynamodb()', () => {
8484
})
8585

8686
const testSingleProxy = (opts) => {
87-
const { http, logicalId, method, intRequestTemplates, uri, intResponseTemplates } = opts
87+
const {
88+
http,
89+
logicalId,
90+
method,
91+
requestParams,
92+
intRequestTemplates,
93+
uri,
94+
intResponseTemplates
95+
} = opts
8896

8997
serverlessApigatewayServiceProxy.validated = {
9098
events: [
@@ -112,6 +120,7 @@ describe('#compileMethodsToDynamodb()', () => {
112120
AuthorizerId: http.auth.authorizerId,
113121
Integration: {
114122
Uri: uri,
123+
RequestParameters: requestParams,
115124
RequestTemplates: intRequestTemplates,
116125
IntegrationResponses: [
117126
{
@@ -158,7 +167,7 @@ describe('#compileMethodsToDynamodb()', () => {
158167
logicalId: `ApiGatewayMethoddynamodb${http.method.substring(0, 1).toUpperCase() +
159168
http.method.substring(1)}`,
160169
method: http.method.toUpperCase(),
161-
requestParams,
170+
requestParams: params.RequestParameters || requestParams,
162171
intRequestTemplates,
163172
uri,
164173
intResponseTemplates
@@ -786,6 +795,7 @@ describe('#compileMethodsToDynamodb()', () => {
786795
]
787796
},
788797
PassthroughBehavior: 'NEVER',
798+
RequestParameters: {},
789799
RequestTemplates: {
790800
'application/json': {
791801
'Fn::Sub': [
@@ -902,6 +912,7 @@ describe('#compileMethodsToDynamodb()', () => {
902912
]
903913
},
904914
PassthroughBehavior: 'NEVER',
915+
RequestParameters: {},
905916
RequestTemplates: {
906917
'application/json': {
907918
'Fn::Sub': [

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "serverless-apigateway-service-proxy",
33
"version": "2.0.0",
4-
"description": "The Serverless Framewrok plugin for supporting AWS service proxy integration of API Gateway",
4+
"description": "The Serverless Framework plugin for supporting AWS service proxy integration of API Gateway",
55
"main": "lib/index.js",
66
"scripts": {
77
"lint": "eslint .",

0 commit comments

Comments
 (0)