serverless-api-gateway-caching
Advanced tools
Comparing version 1.0.0-rc9 to 1.0.0
{ | ||
"name": "serverless-api-gateway-caching", | ||
"version": "1.0.0-rc9", | ||
"description": "", | ||
"version": "1.0.0", | ||
"description": "A plugin for the serverless framework which helps with configuring caching for API Gateway endpoints.", | ||
"main": "src/apiGatewayCachingPlugin.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "mocha --recursive test/**/*.js -t 5000" | ||
}, | ||
"keywords": [ | ||
"serverless", | ||
"aws", | ||
"api", | ||
"gateway", | ||
"rest", | ||
"response", | ||
"caching" | ||
], | ||
"author": "Diana Ionita", | ||
@@ -13,4 +22,19 @@ "license": "ISC", | ||
"aws-sdk": "^2.310.0", | ||
"lodash.get": "^4.4.2", | ||
"lodash.isempty": "^4.4.0" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/DianaIonita/serverless-api-gateway-caching/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/DianaIonita/serverless-api-gateway-caching" | ||
}, | ||
"devDependencies": { | ||
"aws-sdk-mock": "^4.1.0", | ||
"chai": "^4.1.2", | ||
"chance": "^1.0.16", | ||
"mocha": "^5.2.0", | ||
"mocha-junit-reporter": "^1.18.0" | ||
} | ||
} |
# serverless-api-gateway-caching | ||
[![CircleCI](https://circleci.com/gh/DianaIonita/serverless-api-gateway-caching.svg?style=svg)](https://circleci.com/gh/DianaIonita/serverless-api-gateway-caching) | ||
## Intro | ||
A plugin for the serverless framework which helps with configuring caching for API Gateway endpoints. | ||
## Good to know | ||
If you enable caching globally, it does NOT automatically enable caching for your endpoints - you have to be explicit about which endpoints should have caching enabled. | ||
However, disabling caching globally disables it across endpoints. | ||
## Example | ||
@@ -16,4 +22,4 @@ | ||
enabled: true | ||
clusterSize: '0.5' | ||
ttlInSeconds: 300 | ||
clusterSize: '0.5' # defaults to '0.5' | ||
ttlInSeconds: 300 # defaults to the maximum allowed: 3600 | ||
@@ -32,3 +38,3 @@ functions: | ||
# Responses are cached based the 'pawId' path parameter and the 'Accept-Language' header | ||
# Responses are cached based on the 'pawId' path parameter and the 'Accept-Language' header | ||
get-cat-by-paw-id: | ||
@@ -49,1 +55,7 @@ handler: rest_api/cat/get/handler.handle | ||
``` | ||
## Limitations | ||
* For HTTP method `ANY`, caching will be enabled only for the `GET` method and disabled for the other methods. | ||
## Currently not supported: | ||
* lambda functions with many http events |
@@ -20,10 +20,6 @@ 'use strict'; | ||
createSettings() { | ||
this.settings = new ApiGatewayCachingSettings(this.serverless); | ||
this.settings = new ApiGatewayCachingSettings(this.serverless, this.options); | ||
} | ||
updateCloudFormationTemplate() { | ||
if (!this.settings.cachingEnabled) { | ||
return; | ||
} | ||
let restApiId = { | ||
@@ -39,2 +35,7 @@ Ref: 'ApiGatewayRestApi', | ||
}; | ||
// if caching is not defined or disabled | ||
if (!this.settings.cachingEnabled) { | ||
return; | ||
} | ||
@@ -45,9 +46,3 @@ return addPathParametersCacheConfig(this.settings, this.serverless); | ||
updateStage() { | ||
if (!this.settings.cachingEnabled) { | ||
return; | ||
} | ||
serverless.cli.log(`[serverless-api-gateway-caching] Updating API Gateway cache settings.`); | ||
return updateStageCacheSettings(this.settings, this.serverless).then(() => { | ||
serverless.cli.log(`[serverless-api-gateway-caching] Done updating API Gateway cache settings.`); | ||
}); | ||
return updateStageCacheSettings(this.settings, this.serverless); | ||
} | ||
@@ -54,0 +49,0 @@ } |
const isEmpty = require('lodash.isempty'); | ||
const get = require('lodash.get'); | ||
@@ -11,4 +12,5 @@ class ApiGatewayEndpointCachingSettings { | ||
this.cachingEnabled = false; | ||
return; | ||
} | ||
this.cachingEnabled = cachingConfig.enabled; | ||
this.cachingEnabled = globalSettings.cachingEnabled ? cachingConfig.enabled : false; | ||
this.cacheTtlInSeconds = cachingConfig.ttlInSeconds || globalSettings.cacheTtlInSeconds; | ||
@@ -20,12 +22,23 @@ this.cacheKeyParameters = cachingConfig.cacheKeyParameters; | ||
class ApiGatewayCachingSettings { | ||
constructor(serverless) { | ||
if (!serverless.service.custom.apiGatewayCaching) { | ||
this.cachingEnabled = false; | ||
constructor(serverless, options) { | ||
const DEFAULT_CACHE_CLUSTER_SIZE = '0.5'; | ||
const DEFAULT_TTL = 3600; | ||
if (!get(serverless, 'service.custom.apiGatewayCaching')) { | ||
return; | ||
} | ||
this.cachingEnabled = serverless.service.custom.apiGatewayCaching.enabled; | ||
this.cacheClusterSize = serverless.service.custom.apiGatewayCaching.clusterSize; | ||
this.cacheTtlInSeconds = serverless.service.custom.apiGatewayCaching.ttlInSeconds; | ||
if (options) { | ||
this.stage = options.stage || serverless.service.provider.stage; | ||
this.region = options.region || serverless.service.provider.region; | ||
} else { | ||
this.stage = serverless.service.provider.stage; | ||
this.region = serverless.service.provider.region; | ||
} | ||
this.endpointSettings = []; | ||
this.cacheClusterSize = serverless.service.custom.apiGatewayCaching.clusterSize || DEFAULT_CACHE_CLUSTER_SIZE; | ||
this.cacheTtlInSeconds = serverless.service.custom.apiGatewayCaching.ttlInSeconds || DEFAULT_TTL; | ||
for (let functionName in serverless.service.functions) { | ||
@@ -40,8 +53,8 @@ let functionSettings = serverless.service.functions[functionName]; | ||
isApiGatewayEndpoint(functionSettings) { | ||
if (!isEmpty(functionSettings.events)) { | ||
if (isEmpty(functionSettings.events)) { | ||
return false; | ||
} | ||
return !isEmpty(functionSettings.events.filter(e => e.http != null)); | ||
return functionSettings.events.filter(e => e.http != null).length > 0; | ||
} | ||
} | ||
module.exports = ApiGatewayCachingSettings |
@@ -23,4 +23,4 @@ const isEmpty = require('lodash.isempty'); | ||
const getApiGatewayMethodFor = (functionName, serverless) => { | ||
const fullFunctionName = `${serverless.service.service}-${serverless.service.custom.stage}-${functionName}`; | ||
const getApiGatewayMethodFor = (functionName, stage, serverless) => { | ||
const fullFunctionName = `${serverless.service.service}-${stage}-${functionName}`; | ||
const lambdaFunctionResource = getResourceForLambdaFunctionNamed(fullFunctionName, serverless); | ||
@@ -43,3 +43,3 @@ | ||
} | ||
const method = getApiGatewayMethodFor(endpointSettings.functionName, serverless); | ||
const method = getApiGatewayMethodFor(endpointSettings.functionName, settings.stage, serverless); | ||
if (!method.resource.Properties.Integration.CacheKeyParameters) { | ||
@@ -46,0 +46,0 @@ method.resource.Properties.Integration.CacheKeyParameters = []; |
const isEmpty = require('lodash.isempty'); | ||
const AWS = require('aws-sdk'); | ||
const getRestApiId = async serverless => { | ||
const stackName = serverless.providers.aws.naming.getStackName(serverless.service.provider.stage); | ||
const getRestApiId = async (settings, serverless) => { | ||
const stackName = serverless.providers.aws.naming.getStackName(settings.stage); | ||
let stack = await serverless.providers.aws.request('CloudFormation', 'describeStacks', { StackName: stackName }, | ||
serverless.service.provider.stage, | ||
serverless.service.provider.region | ||
settings.stage, | ||
settings.region | ||
); | ||
@@ -34,19 +34,19 @@ | ||
const createPatchForStage = (settings) => { | ||
return [ | ||
{ | ||
let patch = [{ | ||
op: 'replace', | ||
path: '/cacheClusterEnabled', | ||
value: `${settings.cachingEnabled}` | ||
}] | ||
if (settings.cachingEnabled) { | ||
patch.push({ | ||
op: 'replace', | ||
path: '/cacheClusterEnabled', | ||
value: `${settings.cachingEnabled}` | ||
}, | ||
{ | ||
op: 'replace', | ||
path: '/cacheClusterSize', | ||
value: `${settings.cacheClusterSize}` | ||
} | ||
] | ||
}); | ||
} | ||
return patch; | ||
} | ||
const createPatchForEndpoint = (endpointSettings, serverless) => { | ||
const patchPath = patchPathFor(endpointSettings, serverless); | ||
if (!patchPath) return []; | ||
const patchForMethod = (path, method, endpointSettings) => { | ||
let patchPath = patchPathFor(path, method); | ||
let patch = [{ | ||
@@ -56,3 +56,3 @@ op: 'replace', | ||
value: `${endpointSettings.cachingEnabled}` | ||
}] | ||
}]; | ||
if (endpointSettings.cachingEnabled) { | ||
@@ -68,3 +68,3 @@ patch.push({ | ||
const patchPathFor = (endpointSettings, serverless) => { | ||
const createPatchForEndpoint = (endpointSettings, serverless) => { | ||
let lambda = serverless.service.getFunction(endpointSettings.functionName); | ||
@@ -80,4 +80,25 @@ if (isEmpty(lambda.events)) { | ||
let { path, method } = httpEvents[0].http; | ||
let patch = []; | ||
if (method.toUpperCase() == 'ANY') { | ||
let httpMethodsToDisableCacheFor = ['DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT']; // TODO could come from settings, vNext | ||
for (let methodWithCacheDisabled of httpMethodsToDisableCacheFor) { | ||
patch = patch.concat(patchForMethod(path, methodWithCacheDisabled, | ||
{ cachingEnabled: false })); | ||
}; | ||
patch = patch.concat(patchForMethod(path, 'GET', endpointSettings)); | ||
} | ||
else { | ||
patch = patch.concat(patchForMethod(path, method, endpointSettings)); | ||
} | ||
return patch; | ||
} | ||
const patchPathFor = (path, method) => { | ||
let escapedPath = escapeJsonPointer(path); | ||
let patchPath = `~1${escapedPath}/${method.toUpperCase()}`; | ||
if (!escapedPath.startsWith('~1')) { | ||
escapedPath = `~1${escapedPath}`; | ||
} | ||
let patchPath = `${escapedPath}/${method.toUpperCase()}`; | ||
return patchPath; | ||
@@ -87,9 +108,20 @@ } | ||
const updateStageCacheSettings = async (settings, serverless) => { | ||
let restApiId = await getRestApiId(serverless); | ||
// do nothing if caching settings are not defined | ||
if (settings.cachingEnabled == undefined) { | ||
return; | ||
} | ||
let restApiId = await getRestApiId(settings, serverless); | ||
AWS.config.update({ | ||
region: serverless.service.custom.region, | ||
region: settings.region, | ||
}); | ||
let patchOps = createPatchForStage(settings); | ||
let endpointsWithCachingEnabled = settings.endpointSettings.filter(e => e.cachingEnabled); | ||
if (settings.cachingEnabled && isEmpty(endpointsWithCachingEnabled)) { | ||
serverless.cli.log(`[serverless-api-gateway-caching] [WARNING] API Gateway caching is enabled but none of the endpoints have caching enabled`); | ||
} | ||
for (let endpointSettings of settings.endpointSettings) { | ||
@@ -102,8 +134,11 @@ let endpointPatch = createPatchForEndpoint(endpointSettings, serverless); | ||
restApiId, | ||
stageName: serverless.service.custom.stage, | ||
stageName: settings.stage, | ||
patchOperations: patchOps | ||
} | ||
serverless.cli.log(`[serverless-api-gateway-caching] Updating API Gateway cache settings.`); | ||
await apiGateway.updateStage(params).promise(); | ||
serverless.cli.log(`[serverless-api-gateway-caching] Done updating API Gateway cache settings.`); | ||
} | ||
module.exports = updateStageCacheSettings; |
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
15194
8
278
0
1
59
0
3
5
+ Addedlodash.get@^4.4.2
+ Addedlodash.get@4.4.2(transitive)