serverless-api-gateway-throttling
Advanced tools
Comparing version 1.2.2 to 2.0.0-rc1
{ | ||
"name": "serverless-api-gateway-throttling", | ||
"version": "1.2.2", | ||
"version": "2.0.0-rc1", | ||
"description": "A plugin for the Serverless framework which configures throttling for API Gateway endpoints.", | ||
@@ -5,0 +5,0 @@ "main": "src/apiGatewayThrottlingPlugin.js", |
@@ -14,2 +14,3 @@ # serverless-api-gateway-throttling | ||
This plugin makes it easy to configure those limits. | ||
It supports both API Gateway v1 (REST API) and API Gateway v2 (HTTP API). | ||
@@ -91,10 +92,21 @@ ## Good to know | ||
# Throttling is disabled for this endpoint | ||
list-all-items: | ||
list-more-items: | ||
handler: rest_api/items/get/handler.handle | ||
events: | ||
- http: | ||
path: /items | ||
path: /more-items | ||
method: get | ||
throttling: | ||
disabled: true | ||
# Also supports httpApi | ||
list-http-api-items: | ||
handler: rest_api/items/get/handler.handle | ||
events: | ||
- httpApi: | ||
path: /http-api-items | ||
method: get | ||
throttling: | ||
maxRequestsPerSecond: 3000 | ||
maxConcurrentRequests: 1000 | ||
``` |
@@ -38,7 +38,15 @@ 'use strict'; | ||
if (!this.thereIsARestApi) { | ||
this.serverless.cli.log(`[serverless-api-gateway-throttling] No REST API found. Throttling settings will be ignored.`); | ||
return; | ||
this.serverless.cli.log(`[serverless-api-gateway-throttling] No REST API found. Throttling settings will be ignored for REST API endpoints.`); | ||
} | ||
else { | ||
outputRestApiIdTo(this.serverless); | ||
} | ||
outputRestApiIdTo(this.serverless); | ||
this.thereIsAHttpApi = await httpApiExists(this.serverless); | ||
if (!this.thereIsAHttpApi) { | ||
this.serverless.cli.log(`[serverless-api-gateway-throttling] No HTTP API (API Gateway v2) found. Throttling settings will be ignored for HTTP API endpoints.`); | ||
} | ||
else { | ||
outputHttpApiIdTo(this.serverless); | ||
} | ||
} | ||
@@ -45,0 +53,0 @@ |
@@ -13,8 +13,12 @@ 'use strict'; | ||
const isHttpApiEndpoint = event => { | ||
return event.httpApi ? true : false; | ||
} | ||
class ApiGatewayEndpointThrottlingSettings { | ||
constructor(functionName, event, globalSettings) { | ||
constructor(functionName, event, eventType, globalSettings) { | ||
this.functionName = functionName; | ||
if (typeof (event.http) === 'string') { | ||
let parts = event.http.split(' '); | ||
if (typeof (event[eventType]) === 'string') { | ||
let parts = event[eventType].split(' '); | ||
this.method = parts[0]; | ||
@@ -24,7 +28,7 @@ this.path = parts[1]; | ||
else { | ||
this.path = event.http.path; | ||
this.method = event.http.method; | ||
this.path = event[eventType].path; | ||
this.method = event[eventType].method; | ||
} | ||
const throttlingDisabled = get(event.http.throttling, 'disabled') == true; | ||
const throttlingDisabled = get(event[eventType].throttling, 'disabled') == true; | ||
if (throttlingDisabled) { | ||
@@ -37,4 +41,4 @@ // https://github.com/DianaIonita/serverless-api-gateway-throttling/issues/5 | ||
else { | ||
this.maxRequestsPerSecond = get(event.http.throttling, 'maxRequestsPerSecond', globalSettings.maxRequestsPerSecond); | ||
this.maxConcurrentRequests = get(event.http.throttling, 'maxConcurrentRequests', globalSettings.maxConcurrentRequests); | ||
this.maxRequestsPerSecond = get(event[eventType].throttling, 'maxRequestsPerSecond', globalSettings.maxRequestsPerSecond); | ||
this.maxConcurrentRequests = get(event[eventType].throttling, 'maxConcurrentRequests', globalSettings.maxConcurrentRequests); | ||
} | ||
@@ -59,3 +63,4 @@ } | ||
this.endpointSettings = []; | ||
this.restEndpointSettings = []; | ||
this.httpApiEndpointSettings = []; | ||
@@ -69,4 +74,7 @@ for (let functionName in serverless.service.functions) { | ||
if (isApiGatewayEndpoint(event)) { | ||
this.endpointSettings.push(new ApiGatewayEndpointThrottlingSettings(functionName, event, this)) | ||
this.restEndpointSettings.push(new ApiGatewayEndpointThrottlingSettings(functionName, event, 'http', this)) | ||
} | ||
if (isHttpApiEndpoint(event)) { | ||
this.httpApiEndpointSettings.push(new ApiGatewayEndpointThrottlingSettings(functionName, event, 'httpApi', this)) | ||
} | ||
} | ||
@@ -73,0 +81,0 @@ } |
@@ -38,2 +38,23 @@ String.prototype.replaceAll = function (search, replacement) { | ||
const httpApiEventOf = (lambda, endpointSettings) => { | ||
let httpApiEvents = lambda.events.filter(e => e.httpApi != undefined) | ||
.map(e => { | ||
if (typeof (e.http) === 'string') { | ||
let parts = e.http.split(' '); | ||
return { | ||
method: parts[0], | ||
path: parts[1] | ||
} | ||
} else { | ||
return { | ||
method: e.http.method, | ||
path: e.http.path | ||
} | ||
} | ||
}); | ||
return httpApiEvents.filter(e => e.path = endpointSettings.path || "/" + e.path === endpointSettings.path) | ||
.filter(e => e.method.toUpperCase() == endpointSettings.method.toUpperCase())[0]; | ||
} | ||
const patchPathFor = (path, method) => { | ||
@@ -50,3 +71,4 @@ let escapedPath = escapeJsonPointer(path); | ||
patchPathFor, | ||
httpEventOf | ||
httpEventOf, | ||
httpApiEventOf | ||
} |
@@ -79,4 +79,4 @@ 'use strict'; | ||
for (const endpointSettings of settings.endpointSettings) { | ||
const endpointPatch = createPatchForEndpoint(endpointSettings, serverless); | ||
for (const restEndpointSettings of settings.restEndpointSettings) { | ||
const endpointPatch = createPatchForEndpoint(restEndpointSettings, serverless); | ||
patchOps = patchOps.concat(endpointPatch); | ||
@@ -83,0 +83,0 @@ } |
@@ -65,2 +65,7 @@ 'use strict'; | ||
const configuredRestApiId = getConfiguredRestApiId(serverless); | ||
if (configuredRestApiId) { | ||
return configuredRestApiId; | ||
} | ||
const stack = await getAlreadyDeployedStack(serverless, settings); | ||
@@ -67,0 +72,0 @@ const outputs = stack.Stacks[0].Outputs; |
'use strict'; | ||
const isEmpty = require('lodash.isempty'); | ||
const { retrieveRestApiId } = require('./restApiId'); | ||
const { httpEventOf, patchPathFor } = require('./lib'); | ||
const MAX_PATCH_OPERATIONS_PER_STAGE_UPDATE = 80; | ||
const { updateRestApi } = require('./updateRestApiStageThrottling'); | ||
const { updateHttpApi } = require('./updateHttpApiStageThrottling'); | ||
const createPatchForStage = (settings) => { | ||
let patch = [{ | ||
op: 'replace', | ||
path: '/*/*/throttling/rateLimit', | ||
value: `${settings.maxRequestsPerSecond}` | ||
}, | ||
{ | ||
op: 'replace', | ||
path: '/*/*/throttling/burstLimit', | ||
value: `${settings.maxConcurrentRequests}` | ||
}]; | ||
return patch; | ||
} | ||
const patchForMethod = (path, method, endpointSettings) => { | ||
let patchPath = patchPathFor(path, method); | ||
let patch = [{ | ||
op: 'replace', | ||
path: `/${patchPath}/throttling/rateLimit`, | ||
value: `${endpointSettings.maxRequestsPerSecond}` | ||
}, | ||
{ | ||
op: 'replace', | ||
path: `/${patchPath}/throttling/burstLimit`, | ||
value: `${endpointSettings.maxConcurrentRequests}` | ||
}] | ||
return patch; | ||
} | ||
const createPatchForEndpoint = (endpointSettings, serverless) => { | ||
let lambda = serverless.service.getFunction(endpointSettings.functionName); | ||
if (isEmpty(lambda.events)) { | ||
serverless.cli.log(`[serverless-api-gateway-throttling] Lambda ${endpointSettings.functionName} has not defined events.`); | ||
return; | ||
} | ||
const httpEvent = httpEventOf(lambda, endpointSettings); | ||
if (isEmpty(httpEvent)) { | ||
serverless.cli.log(`[serverless-api-gateway-throttling] Lambda ${endpointSettings.functionName} has not defined any HTTP events.`); | ||
return; | ||
} | ||
let { path, method } = httpEvent; | ||
let patch = []; | ||
if (method.toUpperCase() == 'ANY') { | ||
let httpMethodsToConfigureThrottlingFor = ['GET', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT']; | ||
for (let methodWithThrottlingSettings of httpMethodsToConfigureThrottlingFor) { | ||
patch = patch.concat(patchForMethod(path, methodWithThrottlingSettings, endpointSettings)); | ||
}; | ||
} | ||
else { | ||
patch = patch.concat(patchForMethod(path, method, endpointSettings)); | ||
} | ||
return patch; | ||
} | ||
const updateStageFor = async (serverless, params, stage, region) => { | ||
const chunkSize = MAX_PATCH_OPERATIONS_PER_STAGE_UPDATE; | ||
const { patchOperations } = params; | ||
const paramsInChunks = []; | ||
if (patchOperations.length > chunkSize) { | ||
for (let i = 0; i < patchOperations.length; i += chunkSize) { | ||
paramsInChunks.push({ | ||
restApiId: params.restApiId, | ||
stageName: params.stageName, | ||
patchOperations: patchOperations.slice(i, i + chunkSize) | ||
}); | ||
} | ||
} | ||
else { | ||
paramsInChunks.push(params); | ||
} | ||
for (let index in paramsInChunks) { | ||
serverless.cli.log(`[serverless-api-gateway-throttling] Updating API Gateway throttling settings (${parseInt(index) + 1} of ${paramsInChunks.length}).`); | ||
await serverless.providers.aws.request('APIGateway', 'updateStage', paramsInChunks[index], stage, region); | ||
} | ||
serverless.cli.log(`[serverless-api-gateway-throttling] Done updating API Gateway throttling settings.`); | ||
} | ||
const updateStageThrottling = async (settings, serverless) => { | ||
@@ -95,22 +12,6 @@ if (isEmpty(settings)) { | ||
const restApiId = await retrieveRestApiId(serverless, settings); | ||
let patchOps = createPatchForStage(settings); | ||
for (const endpointSettings of settings.endpointSettings) { | ||
const endpointPatch = createPatchForEndpoint(endpointSettings, serverless); | ||
patchOps = patchOps.concat(endpointPatch); | ||
} | ||
const { stage, region } = settings; | ||
const params = { | ||
restApiId, | ||
stageName: stage, | ||
patchOperations: patchOps | ||
} | ||
await updateStageFor(serverless, params, stage, region); | ||
await updateRestApi(settings, serverless); | ||
await updateHttpApi(settings, serverless); | ||
} | ||
module.exports = updateStageThrottling; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29476
12
615
111
2