serverless-reqvalidator-plugin
Version:
Serverless plugin for setting request validation
151 lines (130 loc) • 4.51 kB
JavaScript
;
/**
* Adds using of custom created request validator on specific functions by
* adding `reqValidatorName`
*
* Usage:
*
* myFuncGetItem:
* handler: myFunc.get
* name: ${self:provider.stage}-myFunc-get-item
* events:
* - http:
* method: GET
* path: mypath
* cors: true
* reqValidatorName: 'xyz'
*
* Alternative usage:
*
* myFuncGetItem:
* handler: myFunc.get
* name: ${self:provider.stage}-myFunc-get-item
* events:
* - http:
* method: GET
* path: mypath
* cors: true
* reqValidatorName:
* Fn::ImportValue: 'my-import-value'
*
* Use request validator by Id:
*
* myFuncGetItem:
* handler: myFunc.get
* name: ${self:provider.stage}-myFunc-get-item
* events:
* - http:
* method: GET
* path: mypath
* cors: true
* reqValidatorName:
* id: 'g5ch0h'
*
*
*
* Resources used:
* - https://www.snip2code.com/Snippet/1467589/adds-the-posibility-to-configure-AWS_IAM/
*/
const ServerlessReqValidatorPluginConfigSchema = {
properties: {
reqValidatorName: {
anyOf: [
{ type: 'string' },
{ type: 'object',
properties: {
'Fn::ImportValue': { type: 'string' }
},
required: ['Fn::ImportValue'],
},
{ type: 'object',
properties: {
id: { type: 'string' },
},
required: ['id'],
},
]
},
},
}
class ServerlessReqValidatorPlugin {
constructor(serverless, options) {
this.serverless = serverless;
this.options = options;
this.provider = this.serverless.getProvider('aws');
const naming = this.serverless.providers.aws.naming;
this.getMethodLogicalId = naming.getMethodLogicalId.bind(naming);
this.normalizePath = naming.normalizePath.bind(naming);
this._beforeDeploy = this.beforeDeploy.bind(this)
// Create schema for your properties. For reference use https://github.com/ajv-validator/ajv
serverless.configSchemaHandler.defineFunctionEventProperties('aws', 'http', ServerlessReqValidatorPluginConfigSchema);
this.hooks = {
'before:package:finalize': this._beforeDeploy
};
}
beforeDeploy() {
const resources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources
this.serverless.service.getAllFunctions().forEach((functionName) => {
const functionObject = this.serverless.service.functions[functionName];
functionObject.events.forEach(event => {
if (!event.http) { return; }
const reqValidatorName = event.http.reqValidatorName;
if (reqValidatorName) {
let path;
let method;
if (typeof event.http === 'object') {
path = event.http.path;
method = event.http.method;
} else if (typeof event.http === 'string') {
path = event.http.split(' ')[1];
method = event.http.split(' ')[0];
}
const resourcesArray = path.split('/');
// resource name is the last element in the endpoint. It's not unique.
const resourceName = path.split('/')[path.split('/').length - 1];
const normalizedResourceName = resourcesArray.map(this.normalizePath).join('');
const normalizedMethod = method[0].toUpperCase() + method.substr(1).toLowerCase();
const methodName = `ApiGatewayMethod${normalizedResourceName}${normalizedMethod}`;
switch (typeof reqValidatorName) {
case 'object':
if (reqValidatorName['Fn::ImportValue']) {
resources[methodName].Properties.RequestValidatorId = reqValidatorName;
} else if (reqValidatorName['id']) {
resources[methodName].Properties.RequestValidatorId = reqValidatorName['id']
} else { // other use cases should be added here
resources[methodName].Properties.RequestValidatorId = reqValidatorName;
}
break;
case 'string':
default:
resources[methodName].Properties.RequestValidatorId = { "Ref": `${reqValidatorName}` };
break;
}
}
});
}
)
}
}
module.exports = ServerlessReqValidatorPlugin;
module.exports.ServerlessReqValidatorPluginConfigSchema = ServerlessReqValidatorPluginConfigSchema;