From eacae9a64da22ddf0fca8beff580a951e20d4fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Barthelet?= Date: Mon, 4 Jan 2021 10:04:57 +0100 Subject: [PATCH] feat(AWS API Gateway): Move api-specific keys to `provider.apiGateway` --- docs/deprecations.md | 10 ++ docs/providers/aws/events/apigateway.md | 91 +++++++++---------- docs/providers/aws/guide/serverless.yml.md | 64 ++++++------- lib/plugins/aws/info/getApiKeyValues.js | 4 +- .../compile/events/apiGateway/index.js | 13 +++ .../compile/events/apiGateway/lib/apiKeys.js | 16 ++-- .../lib/hack/disassociateUsagePlan.js | 4 +- .../compile/events/apiGateway/lib/restApi.js | 10 +- .../events/apiGateway/lib/usagePlan.js | 59 ++++++------ .../events/apiGateway/lib/usagePlanKeys.js | 7 +- lib/plugins/aws/provider.js | 70 ++++++++------ .../apiGatewayExtended/serverless.yml | 7 +- .../plugins/aws/info/getApiKeyValues.test.js | 8 +- .../events/apiGateway/lib/apiKeys.test.js | 63 +++++++------ .../lib/hack/disassociateUsagePlan.test.js | 4 +- .../events/apiGateway/lib/restApi.test.js | 24 ++--- .../events/apiGateway/lib/usagePlan.test.js | 80 ++++++++-------- .../apiGateway/lib/usagePlanKeys.test.js | 23 +++-- 18 files changed, 311 insertions(+), 246 deletions(-) diff --git a/docs/deprecations.md b/docs/deprecations.md index d7917e8dc..2eb1e68d8 100644 --- a/docs/deprecations.md +++ b/docs/deprecations.md @@ -6,6 +6,16 @@ layout: Doc # Serverless Framework Deprecations +
 
+ +## API Gateway specific configuration + +Please use `provider.apiGateway.apiKeys` instead of `provider.apiKeys`. +Please use `provider.apiGateway.resourcePolicy` instead of `provider.resourcePolicy`. +Please use `provider.apiGateway.usagePlan` instead of `provider.usagePlan`. + +Starting with v3.0.0, API Gateway-specific configuration keys `apiKeys`, `resourcePolicy` and `usagePlan` will be relocated from `provider` to `provider.apiGateway`. +
 
## Parameterized `org`, `app`, `service`, `stage`, and `region` usage diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index 6680fc31c..630317b83 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -608,12 +608,7 @@ In case an exception is thrown in your lambda function AWS will send an error me ### Setting API keys for your Rest API -You can specify a list of API keys to be used by your service Rest API by adding an `apiKeys` array property to the -`provider` object in `serverless.yml`. You'll also need to explicitly specify which endpoints are `private` and require -one of the api keys to be included in the request by adding a `private` boolean property to the `http` event object you -want to set as private. API Keys are created globally, so if you want to deploy your service to different stages make sure -your API key contains a stage variable as defined below. When using API keys, you can optionally define usage plan quota -and throttle, using `usagePlan` object. +You can specify a list of API keys to be used by your service Rest API by adding an `apiKeys` array property to the `provider.apiGateway` object in `serverless.yml`. You'll also need to explicitly specify which endpoints are `private` and require one of the api keys to be included in the request by adding a `private` boolean property to the `http` event object you want to set as private. API Keys are created globally, so if you want to deploy your service to different stages make sure your API key contains a stage variable as defined below. When using API keys, you can optionally define usage plan quota and throttle, using `usagePlan` object. When setting the value, you need to be aware that changing value will require replacement and CloudFormation doesn't allow two API keys with the same name. It means that you need to change the name also when changing the value. If you don't care @@ -625,23 +620,24 @@ Here's an example configuration for setting API keys for your service Rest API: service: my-service provider: name: aws - apiKeys: - - myFirstKey - - ${opt:stage}-myFirstKey - - ${env:MY_API_KEY} # you can hide it in a serverless variable - - name: myThirdKey - value: myThirdKeyValue - - value: myFourthKeyValue # let cloudformation name the key (recommended when setting api key value) - description: Api key description # Optional - customerId: A string that will be set as the customerID for the key # Optional - usagePlan: - quota: - limit: 5000 - offset: 2 - period: MONTH - throttle: - burstLimit: 200 - rateLimit: 100 + apiGateway: + apiKeys: + - myFirstKey + - ${opt:stage}-myFirstKey + - ${env:MY_API_KEY} # you can hide it in a serverless variable + - name: myThirdKey + value: myThirdKeyValue + - value: myFourthKeyValue # let cloudformation name the key (recommended when setting api key value) + description: Api key description # Optional + customerId: A string that will be set as the customerID for the key # Optional + usagePlan: + quota: + limit: 5000 + offset: 2 + period: MONTH + throttle: + burstLimit: 200 + rateLimit: 100 functions: hello: events: @@ -661,30 +657,31 @@ You can also setup multiple usage plans for your API. In this case you need to m service: my-service provider: name: aws - apiKeys: - - free: - - myFreeKey - - ${opt:stage}-myFreeKey - - paid: - - myPaidKey - - ${opt:stage}-myPaidKey - usagePlan: - - free: - quota: - limit: 5000 - offset: 2 - period: MONTH - throttle: - burstLimit: 200 - rateLimit: 100 - - paid: - quota: - limit: 50000 - offset: 1 - period: MONTH - throttle: - burstLimit: 2000 - rateLimit: 1000 + apiGateway: + apiKeys: + - free: + - myFreeKey + - ${opt:stage}-myFreeKey + - paid: + - myPaidKey + - ${opt:stage}-myPaidKey + usagePlan: + - free: + quota: + limit: 5000 + offset: 2 + period: MONTH + throttle: + burstLimit: 200 + rateLimit: 100 + - paid: + quota: + limit: 50000 + offset: 1 + period: MONTH + throttle: + burstLimit: 2000 + rateLimit: 1000 functions: hello: events: diff --git a/docs/providers/aws/guide/serverless.yml.md b/docs/providers/aws/guide/serverless.yml.md index f2e8409ab..b138288e4 100644 --- a/docs/providers/aws/guide/serverless.yml.md +++ b/docs/providers/aws/guide/serverless.yml.md @@ -87,13 +87,6 @@ provider: environment: # Service wide environment variables serviceEnvVar: 123456789 endpointType: regional # Optional endpoint configuration for API Gateway REST API. Default is Edge. - apiKeys: # List of API keys to be used by your service API Gateway REST API - - myFirstKey - value: myFirstKeyValue - description: myFirstKeyDescription - customerId: myFirstKeyCustomerId - - ${opt:stage}-myFirstKey - - ${env:MY_API_KEY} # you can hide it in a serverless variable apiGateway: # Optional API Gateway global config restApiId: xxxxxxxxxx # REST API resource ID. Default is generated by the framework restApiRootResourceId: xxxxxxxxxx # Root resource ID, represent as / path @@ -102,12 +95,37 @@ provider: '/users/create': xxxxxxxxxx websocketApiId: # Websocket API resource ID. Default is generated by the framework apiKeySourceType: HEADER # Source of API key for usage plan. HEADER or AUTHORIZER. + apiKeys: # List of API keys to be used by your service API Gateway REST API + - myFirstKey + value: myFirstKeyValue + description: myFirstKeyDescription + customerId: myFirstKeyCustomerId + - ${opt:stage}-myFirstKey + - ${env:MY_API_KEY} # you can hide it in a serverless variable minimumCompressionSize: 1024 # Compress response when larger than specified size in bytes (must be between 0 and 10485760) description: Some Description # Optional description for the API Gateway stage deployment binaryMediaTypes: # Optional binary media types the API might return - '*/*' metrics: false # Optional detailed Cloud Watch Metrics shouldStartNameWithService: false # Use `${service}-${stage}` naming for API Gateway. Will be `true` by default in next major version. + resourcePolicy: + - Effect: Allow + Principal: '*' + Action: execute-api:Invoke + Resource: + - execute-api:/*/*/* + Condition: + IpAddress: + aws:SourceIp: + - '123.123.123.123' + usagePlan: # Optional usage plan configuration + quota: + limit: 5000 + offset: 2 + period: MONTH + throttle: + burstLimit: 200 + rateLimit: 100 alb: targetGroupPrefix: xxxxxxxxxx # Optional prefix to prepend when generating names for target groups authorizers: @@ -152,14 +170,6 @@ provider: audience: - xxxx - xxxx - usagePlan: # Optional usage plan configuration - quota: - limit: 5000 - offset: 2 - period: MONTH - throttle: - burstLimit: 200 - rateLimit: 100 stackTags: # Optional CF stack tags key: value iamManagedPolicies: # Optional IAM Managed Policies, which allows to include the policies into IAM Role @@ -200,23 +210,13 @@ provider: stackParameters: - ParameterKey: 'Keyname' ParameterValue: 'Value' - resourcePolicy: - - Effect: Allow - Principal: '*' - Action: execute-api:Invoke - Resource: - - execute-api:/*/*/* - Condition: - IpAddress: - aws:SourceIp: - - '123.123.123.123' - rollbackConfiguration: - MonitoringTimeInMinutes: 20 - RollbackTriggers: - - Arn: arn:aws:cloudwatch:us-east-1:000000000000:alarm:health - Type: AWS::CloudWatch::Alarm - - Arn: arn:aws:cloudwatch:us-east-1:000000000000:alarm:latency - Type: AWS::CloudWatch::Alarm + rollbackConfiguration: + MonitoringTimeInMinutes: 20 + RollbackTriggers: + - Arn: arn:aws:cloudwatch:us-east-1:000000000000:alarm:health + Type: AWS::CloudWatch::Alarm + - Arn: arn:aws:cloudwatch:us-east-1:000000000000:alarm:latency + Type: AWS::CloudWatch::Alarm tags: # Optional service wide function tags foo: bar baz: qux diff --git a/lib/plugins/aws/info/getApiKeyValues.js b/lib/plugins/aws/info/getApiKeyValues.js index f5fc61dd2..b3c2ecc71 100644 --- a/lib/plugins/aws/info/getApiKeyValues.js +++ b/lib/plugins/aws/info/getApiKeyValues.js @@ -9,7 +9,9 @@ module.exports = { info.apiKeys = []; // check if the user has set api keys - const apiKeyDefinitions = this.serverless.service.provider.apiKeys; + const apiKeyDefinitions = + _.get(this.serverless.service.provider.apiGateway, 'apiKeys') || + this.serverless.service.provider.apiKeys; const apiKeyNames = []; if (Array.isArray(apiKeyDefinitions) && apiKeyDefinitions.length) { apiKeyDefinitions.forEach(definition => { diff --git a/lib/plugins/aws/package/compile/events/apiGateway/index.js b/lib/plugins/aws/package/compile/events/apiGateway/index.js index a42e96ffc..2376fd155 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/index.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/index.js @@ -249,6 +249,19 @@ class AwsCompileApigEvents { 'to adapt to the new behavior now.' ); } + if ( + this.serverless.service.provider.name === 'aws' && + (this.serverless.service.provider.apiKeys || + this.serverless.service.provider.resourcePolicy || + this.serverless.service.provider.usagePlan) + ) { + this.serverless._logDeprecation( + 'AWS_API_GATEWAY_SPECIFIC_KEYS', + 'Starting with next major version, API Gateway-specific configuration keys ' + + '"apiKeys", "resourcePolicy" and "usagePlan" will be relocated from "provider" ' + + 'to "provider.apiGateway"' + ); + } }, 'package:compileEvents': () => { this.validated = this.validate(); diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.js index b903cead4..b1c27d168 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.js @@ -31,18 +31,22 @@ function createApiKeyResource(that, apiKey) { module.exports = { compileApiKeys() { - if (this.serverless.service.provider.apiKeys) { + const apiKeys = + _.get(this.serverless.service.provider.apiGateway, 'apiKeys') || + this.serverless.service.provider.apiKeys; + if (apiKeys) { const resources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources; let keyNumber = 0; - this.serverless.service.provider.apiKeys.forEach(apiKeyDefinition => { + apiKeys.forEach(apiKeyDefinition => { // if multiple API key types are used const name = Object.keys(apiKeyDefinition)[0]; + const usagePlan = + _.get(this.serverless.service.provider.apiGateway, 'usagePlan') || + this.serverless.service.provider.usagePlan; if ( _.isObject(apiKeyDefinition) && - Array.isArray(this.serverless.service.provider.usagePlan) && - _.flatten( - this.serverless.service.provider.usagePlan.map(item => Object.keys(item)) - ).includes(name) + Array.isArray(usagePlan) && + _.flatten(usagePlan.map(item => Object.keys(item))).includes(name) ) { keyNumber = 0; apiKeyDefinition[name].forEach(key => { diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.js index f1ed33ae3..174e73f88 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.js @@ -5,7 +5,9 @@ const _ = require('lodash'); module.exports = { disassociateUsagePlan() { - const apiKeys = this.serverless.service.provider.apiKeys; + const apiKeys = + _.get(this.serverless.service.provider.apiGateway, 'apiKeys') || + this.serverless.service.provider.apiKeys; if (apiKeys && apiKeys.length) { this.serverless.cli.log('Removing usage plan association...'); diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.js index 252198eb2..6975a205c 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.js @@ -54,13 +54,13 @@ module.exports = { }, }); - if ( - this.serverless.service.provider.resourcePolicy && - Object.keys(this.serverless.service.provider.resourcePolicy).length - ) { + const resourcePolicy = + _.get(this.serverless.service.provider.apiGateway, 'resourcePolicy') || + this.serverless.service.provider.resourcePolicy; + if (resourcePolicy && Object.keys(resourcePolicy).length) { const policy = { Version: '2012-10-17', - Statement: this.serverless.service.provider.resourcePolicy, + Statement: resourcePolicy, }; _.merge( this.serverless.service.provider.compiledCloudFormationTemplate.Resources[ diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.js index 79609f7d6..b3cdbd82f 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.js @@ -21,6 +21,9 @@ function createUsagePlanResource(that, name) { }, }; const template = _.cloneDeep(resourceTemplate); + const usagePlan = + _.get(that.serverless.service.provider.apiGateway, 'usagePlan') || + that.serverless.service.provider.usagePlan; // this is done for backward compatibility if (name === 'default') { // create old legacy resources @@ -31,39 +34,36 @@ function createUsagePlanResource(that, name) { that.serverless.service.service } ${that.provider.getStage()} stage`; // assign quota - if (_.get(that.serverless.service.provider, 'usagePlan.quota')) { + if (_.get(usagePlan, 'quota')) { _.merge(template, { Properties: { Quota: _.merge( - { Limit: that.serverless.service.provider.usagePlan.quota.limit }, - { Offset: that.serverless.service.provider.usagePlan.quota.offset }, - { Period: that.serverless.service.provider.usagePlan.quota.period } + { Limit: usagePlan.quota.limit }, + { Offset: usagePlan.quota.offset }, + { Period: usagePlan.quota.period } ), }, }); } // assign throttle - if (_.get(that.serverless.service.provider, 'usagePlan.throttle')) { + if (_.get(usagePlan, 'throttle')) { _.merge(template, { Properties: { Throttle: _.merge( - { BurstLimit: that.serverless.service.provider.usagePlan.throttle.burstLimit }, - { RateLimit: that.serverless.service.provider.usagePlan.throttle.rateLimit } + { BurstLimit: usagePlan.throttle.burstLimit }, + { RateLimit: usagePlan.throttle.rateLimit } ), }, }); } } else { // assign quota - const quotaProperties = that.serverless.service.provider.usagePlan.reduce( - (accum, planObject) => { - if (planObject[name] && planObject[name].quota) { - return planObject[name].quota; - } - return accum; - }, - {} - ); + const quotaProperties = usagePlan.reduce((accum, planObject) => { + if (planObject[name] && planObject[name].quota) { + return planObject[name].quota; + } + return accum; + }, {}); if (Object.keys(quotaProperties).length) { _.merge(template, { Properties: { @@ -76,15 +76,12 @@ function createUsagePlanResource(that, name) { }); } // assign throttle - const throttleProperties = that.serverless.service.provider.usagePlan.reduce( - (accum, planObject) => { - if (planObject[name] && planObject[name].throttle) { - return planObject[name].throttle; - } - return accum; - }, - {} - ); + const throttleProperties = usagePlan.reduce((accum, planObject) => { + if (planObject[name] && planObject[name].throttle) { + return planObject[name].throttle; + } + return accum; + }, {}); if (Object.keys(quotaProperties).length) { _.merge(template, { Properties: { @@ -101,12 +98,18 @@ function createUsagePlanResource(that, name) { module.exports = { compileUsagePlan() { - if (this.serverless.service.provider.usagePlan || this.serverless.service.provider.apiKeys) { + const apiKeys = + _.get(this.serverless.service.provider.apiGateway, 'apiKeys') || + this.serverless.service.provider.apiKeys; + const usagePlan = + _.get(this.serverless.service.provider.apiGateway, 'usagePlan') || + this.serverless.service.provider.usagePlan; + if (usagePlan || apiKeys) { const resources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources; this.apiGatewayUsagePlanNames = []; - if (Array.isArray(this.serverless.service.provider.usagePlan)) { - this.serverless.service.provider.usagePlan.forEach(planObject => { + if (Array.isArray(usagePlan)) { + usagePlan.forEach(planObject => { const usagePlanName = Object.keys(planObject)[0]; const logicalId = this.provider.naming.getUsagePlanLogicalId(usagePlanName); const resourceTemplate = createUsagePlanResource(this, usagePlanName); diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.js index cc86931d1..ce9f8bf0e 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.js @@ -24,11 +24,14 @@ function createUsagePlanKeyResource(that, usagePlanLogicalId, keyNumber, keyName module.exports = { compileUsagePlanKeys() { - if (this.serverless.service.provider.apiKeys) { + const apiKeys = + _.get(this.serverless.service.provider.apiGateway, 'apiKeys') || + this.serverless.service.provider.apiKeys; + if (apiKeys) { const resources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources; let keyNumber = 0; - this.serverless.service.provider.apiKeys.forEach(apiKeyDefinition => { + apiKeys.forEach(apiKeyDefinition => { // if multiple API key types are used const apiKey = Object.entries(apiKeyDefinition)[0]; const name = apiKey[0]; diff --git a/lib/plugins/aws/provider.js b/lib/plugins/aws/provider.js index 57d64db87..9b8f7320a 100644 --- a/lib/plugins/aws/provider.js +++ b/lib/plugins/aws/provider.js @@ -248,6 +248,33 @@ class AwsProvider { type: 'string', pattern: '^execute-api:/', }, + awsApiGatewayApiKeys: { + type: 'array', + items: { + anyOf: [ + { type: 'string' }, + { + type: 'object', + properties: { + name: { type: 'string' }, + value: { type: 'string' }, + description: { type: 'string' }, + customerId: { type: 'string' }, + }, + anyOf: [{ required: ['name'] }, { required: ['value'] }], + additionalProperties: false, + }, + { + type: 'object', + maxProperties: 1, + additionalProperties: { + type: 'array', + items: { type: 'string' }, + }, + }, + ], + }, + }, awsArn: { anyOf: [ { $ref: '#/definitions/awsArnString' }, @@ -515,6 +542,7 @@ class AwsProvider { apiGateway: { type: 'object', properties: { + apiKeys: { $ref: '#/definitions/awsApiGatewayApiKeys' }, apiKeySourceType: { anyOf: ['HEADER', 'AUTHORIZER'].map(caseInsensitive), }, @@ -525,6 +553,7 @@ class AwsProvider { description: { type: 'string' }, metrics: { type: 'boolean' }, minimumCompressionSize: { type: 'integer', minimum: 0, maximum: 10485760 }, + resourcePolicy: { $ref: '#/definitions/awsResourcePolicyStatements' }, restApiId: { $ref: '#/definitions/awsCfInstruction' }, restApiResources: { anyOf: [ @@ -545,37 +574,24 @@ class AwsProvider { }, restApiRootResourceId: { $ref: '#/definitions/awsCfInstruction' }, shouldStartNameWithService: { const: true }, + usagePlan: { + anyOf: [ + apiGatewayUsagePlan, + { + type: 'array', + items: { + type: 'object', + additionalProperties: apiGatewayUsagePlan, + maxProperties: 1, + }, + }, + ], + }, websocketApiId: { $ref: '#/definitions/awsCfInstruction' }, }, additionalProperties: false, }, - apiKeys: { - type: 'array', - items: { - anyOf: [ - { type: 'string' }, - { - type: 'object', - properties: { - name: { type: 'string' }, - value: { type: 'string' }, - description: { type: 'string' }, - customerId: { type: 'string' }, - }, - anyOf: [{ required: ['name'] }, { required: ['value'] }], - additionalProperties: false, - }, - { - type: 'object', - maxProperties: 1, - additionalProperties: { - type: 'array', - items: { type: 'string' }, - }, - }, - ], - }, - }, + apiKeys: { $ref: '#/definitions/awsApiGatewayApiKeys' }, apiName: { type: 'string' }, alb: { type: 'object', diff --git a/test/fixtures/apiGatewayExtended/serverless.yml b/test/fixtures/apiGatewayExtended/serverless.yml index a3dad6449..f7e18131f 100644 --- a/test/fixtures/apiGatewayExtended/serverless.yml +++ b/test/fixtures/apiGatewayExtended/serverless.yml @@ -7,9 +7,10 @@ provider: name: aws runtime: nodejs12.x versionFunctions: false - apiKeys: - - name: ${self:service.name}-api-key-1 - value: ${self:service.name}-api-key-1 + apiGateway: + apiKeys: + - name: ${self:service.name}-api-key-1 + value: ${self:service.name}-api-key-1 functions: # core functions diff --git a/test/unit/lib/plugins/aws/info/getApiKeyValues.test.js b/test/unit/lib/plugins/aws/info/getApiKeyValues.test.js index 191cea0f6..9417eb58b 100644 --- a/test/unit/lib/plugins/aws/info/getApiKeyValues.test.js +++ b/test/unit/lib/plugins/aws/info/getApiKeyValues.test.js @@ -29,7 +29,9 @@ describe('#getApiKeyValues()', () => { it('should add API Key values to this.gatheredData if API key names are available', () => { // set the API Keys for the service - awsInfo.serverless.service.provider.apiKeys = ['foo', 'bar']; + awsInfo.serverless.service.provider.apiGateway = { + apiKeys: ['foo', 'bar'], + }; awsInfo.gatheredData = { info: {}, @@ -87,7 +89,7 @@ describe('#getApiKeyValues()', () => { it('should resolve if AWS does not return API key values', () => { // set the API Keys for the service - awsInfo.serverless.service.provider.apiKeys = ['foo', 'bar']; + awsInfo.serverless.service.provider.apiGateway = { apiKeys: ['foo', 'bar'] }; awsInfo.gatheredData = { info: {}, @@ -112,7 +114,7 @@ describe('#getApiKeyValues()', () => { }); it('should resolve if API key names are not available', () => { - awsInfo.serverless.service.provider.apiKeys = null; + awsInfo.serverless.service.provider.apiGateway = {}; awsInfo.gatheredData = { info: {}, diff --git a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.test.js b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.test.js index 627e8d5e2..ee9b72b8b 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/apiKeys.test.js @@ -27,21 +27,22 @@ describe('#compileApiKeys()', () => { }); it('should support api key notation', () => { - awsCompileApigEvents.serverless.service.provider.apiKeys = [ - '1234567890', - { name: '2345678901' }, - { value: 'valueForKeyWithoutName', description: 'Api key description' }, - { name: '3456789012', value: 'valueForKey3456789012' }, - { - name: '9876543211', - value: 'valueForKey9876543211', - customerId: 'customerid98765', + awsCompileApigEvents.serverless.service.provider.apiGateway = { + apiKeys: [ + '1234567890', + { name: '2345678901' }, + { value: 'valueForKeyWithoutName', description: 'Api key description' }, + { name: '3456789012', value: 'valueForKey3456789012' }, + { + name: '9876543211', + value: 'valueForKey9876543211', + customerId: 'customerid98765', + }, + ], + // Added purely to test https://github.com/serverless/serverless/issues/7844 regression + usagePlan: { + quota: { limit: 5000 }, }, - ]; - - // Added purely to test https://github.com/serverless/serverless/issues/7844 regression - awsCompileApigEvents.serverless.service.provider.usagePlan = { - quota: { limit: 5000 }, }; return awsCompileApigEvents.compileApiKeys().then(() => { @@ -138,21 +139,23 @@ describe('#compileApiKeys()', () => { describe('when using usage plan notation', () => { it('should support usage plan notation', () => { - awsCompileApigEvents.serverless.service.provider.usagePlan = [{ free: [] }, { paid: [] }]; - awsCompileApigEvents.serverless.service.provider.apiKeys = [ - { - free: [ - '1234567890', - { name: '2345678901' }, - { - value: 'valueForKeyWithoutName', - description: 'Api key description', - }, - { name: '3456789012', value: 'valueForKey3456789012' }, - ], - }, - { paid: ['0987654321', 'jihgfedcba'] }, - ]; + awsCompileApigEvents.serverless.service.provider.apiGateway = { + apiKeys: [ + { + free: [ + '1234567890', + { name: '2345678901' }, + { + value: 'valueForKeyWithoutName', + description: 'Api key description', + }, + { name: '3456789012', value: 'valueForKey3456789012' }, + ], + }, + { paid: ['0987654321', 'jihgfedcba'] }, + ], + usagePlan: [{ free: [] }, { paid: [] }], + }; return awsCompileApigEvents.compileApiKeys().then(() => { const expectedApiKeys = { @@ -175,7 +178,7 @@ describe('#compileApiKeys()', () => { { name: 'jihgfedcba', value: undefined, description: undefined }, ], }; - awsCompileApigEvents.serverless.service.provider.apiKeys.forEach(plan => { + awsCompileApigEvents.serverless.service.provider.apiGateway.apiKeys.forEach(plan => { const planName = Object.keys(plan)[0]; // free || paid const apiKeys = expectedApiKeys[planName]; apiKeys.forEach((apiKey, index) => { diff --git a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.test.js b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.test.js index df254e622..5bd08566e 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/hack/disassociateUsagePlan.test.js @@ -63,7 +63,7 @@ describe('#disassociateUsagePlan()', () => { }); it('should remove association from the usage plan', () => { - disassociateUsagePlan.serverless.service.provider.apiKeys = ['apiKey1']; + disassociateUsagePlan.serverless.service.provider.apiGateway = { apiKeys: ['apiKey1'] }; return disassociateUsagePlan.disassociateUsagePlan().then(() => { expect(providerRequestStub.callCount).to.be.equal(3); @@ -95,7 +95,7 @@ describe('#disassociateUsagePlan()', () => { }); it('should resolve if no api keys are given', () => { - disassociateUsagePlan.serverless.service.provider.apiKeys = []; + disassociateUsagePlan.serverless.service.provider.apiGateway = { apiKeys: [] }; return disassociateUsagePlan.disassociateUsagePlan().then(() => { expect(providerRequestStub.callCount).to.be.equal(0); diff --git a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.test.js b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.test.js index 50a021aa9..45dd9ff07 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/restApi.test.js @@ -55,19 +55,21 @@ describe('#compileRestApi()', () => { })); it('should create a REST API resource with resource policy', () => { - awsCompileApigEvents.serverless.service.provider.resourcePolicy = [ - { - Effect: 'Allow', - Principal: '*', - Action: 'execute-api:Invoke', - Resource: ['execute-api:/*/*/*'], - Condition: { - IpAddress: { - 'aws:SourceIp': ['123.123.123.123'], + awsCompileApigEvents.serverless.service.provider.apiGateway = { + resourcePolicy: [ + { + Effect: 'Allow', + Principal: '*', + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'], + Condition: { + IpAddress: { + 'aws:SourceIp': ['123.123.123.123'], + }, }, }, - }, - ]; + ], + }; return awsCompileApigEvents.compileRestApi().then(() => { const resources = awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources; diff --git a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.test.js b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.test.js index 5b6e34c4c..257a7b743 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlan.test.js @@ -28,7 +28,7 @@ describe('#compileUsagePlan()', () => { }); it('should compile default usage plan resource', () => { - serverless.service.provider.apiKeys = ['1234567890']; + serverless.service.provider.apiGateway = { apiKeys: ['1234567890'] }; return awsCompileApigEvents.compileUsagePlan().then(() => { expect( awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources[ @@ -66,15 +66,17 @@ describe('#compileUsagePlan()', () => { }); it('should support custom usage plan resource via single object notation', () => { - serverless.service.provider.usagePlan = { - quota: { - limit: 500, - offset: 10, - period: 'MONTH', - }, - throttle: { - burstLimit: 200, - rateLimit: 100, + serverless.service.provider.apiGateway = { + usagePlan: { + quota: { + limit: 500, + offset: 10, + period: 'MONTH', + }, + throttle: { + burstLimit: 200, + rateLimit: 100, + }, }, }; @@ -139,34 +141,36 @@ describe('#compileUsagePlan()', () => { const logicalIdFree = awsCompileApigEvents.provider.naming.getUsagePlanLogicalId(freePlanName); const logicalIdPaid = awsCompileApigEvents.provider.naming.getUsagePlanLogicalId(paidPlanName); - serverless.service.provider.usagePlan = [ - { - [freePlanName]: { - quota: { - limit: 1000, - offset: 100, - period: 'MONTH', - }, - throttle: { - burstLimit: 1, - rateLimit: 1, + serverless.service.provider.apiGateway = { + usagePlan: [ + { + [freePlanName]: { + quota: { + limit: 1000, + offset: 100, + period: 'MONTH', + }, + throttle: { + burstLimit: 1, + rateLimit: 1, + }, }, }, - }, - { - [paidPlanName]: { - quota: { - limit: 1000000, - offset: 200, - period: 'MONTH', - }, - throttle: { - burstLimit: 1000, - rateLimit: 1000, + { + [paidPlanName]: { + quota: { + limit: 1000000, + offset: 200, + period: 'MONTH', + }, + throttle: { + burstLimit: 1000, + rateLimit: 1000, + }, }, }, - }, - ]; + ], + }; return awsCompileApigEvents.compileUsagePlan().then(() => { // resources for the "free" plan @@ -275,8 +279,8 @@ describe('#compileUsagePlan()', () => { }); it('should compile custom usage plan resource with restApiId provided', () => { - serverless.service.provider.apiKeys = ['1234567890']; awsCompileApigEvents.serverless.service.provider.apiGateway = { + apiKeys: ['1234567890'], restApiId: 'xxxxx', }; @@ -329,7 +333,7 @@ describe('UsagePlan', () => { }; it('Should have values for throttle', () => { - serverlessConfigurationExtension.provider.usagePlan = { throttle }; + serverlessConfigurationExtension.provider.apiGateway = { usagePlan: { throttle } }; return runServerless({ fixture: 'apiGateway', configExt: serverlessConfigurationExtension, @@ -345,7 +349,7 @@ describe('UsagePlan', () => { }); it('Should have values for quota', () => { - serverlessConfigurationExtension.provider.usagePlan = { quota }; + serverlessConfigurationExtension.provider.apiGateway = { usagePlan: { quota } }; return runServerless({ fixture: 'apiGateway', configExt: serverlessConfigurationExtension, @@ -360,7 +364,7 @@ describe('UsagePlan', () => { }); it('Should have values for quota and throttle', () => { - serverlessConfigurationExtension.provider.usagePlan = { throttle, quota }; + serverlessConfigurationExtension.provider.apiGateway = { usagePlan: { throttle, quota } }; return runServerless({ fixture: 'apiGateway', configExt: serverlessConfigurationExtension, diff --git a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.test.js b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.test.js index 85490e500..5be4b3710 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/apiGateway/lib/usagePlanKeys.test.js @@ -30,10 +30,9 @@ describe('#compileUsagePlanKeys()', () => { it('should support api key notation', () => { const defaultUsagePlanLogicalId = awsCompileApigEvents.provider.naming.getUsagePlanLogicalId(); awsCompileApigEvents.apiGatewayUsagePlanNames = ['default']; - awsCompileApigEvents.serverless.service.provider.apiKeys = [ - '1234567890', - { name: 'abcdefghij', value: 'abcdefghijvalue' }, - ]; + awsCompileApigEvents.serverless.service.provider.apiGateway = { + apiKeys: ['1234567890', { name: 'abcdefghij', value: 'abcdefghijvalue' }], + }; return awsCompileApigEvents.compileUsagePlanKeys().then(() => { // key 1 @@ -91,13 +90,15 @@ describe('#compileUsagePlanKeys()', () => { paid: awsCompileApigEvents.provider.naming.getUsagePlanLogicalId(paidUsagePlanName), }; awsCompileApigEvents.apiGatewayUsagePlanNames = [freeUsagePlanName, paidUsagePlanName]; - awsCompileApigEvents.serverless.service.provider.apiKeys = [ - { free: ['1234567890', { name: 'abcdefghij', value: 'abcdefghijvalue' }] }, - { paid: ['0987654321', 'jihgfedcba'] }, - ]; + awsCompileApigEvents.serverless.service.provider.apiGateway = { + apiKeys: [ + { free: ['1234567890', { name: 'abcdefghij', value: 'abcdefghijvalue' }] }, + { paid: ['0987654321', 'jihgfedcba'] }, + ], + }; return awsCompileApigEvents.compileUsagePlanKeys().then(() => { - awsCompileApigEvents.serverless.service.provider.apiKeys.forEach(plan => { + awsCompileApigEvents.serverless.service.provider.apiGateway.apiKeys.forEach(plan => { const planName = Object.keys(plan)[0]; // free || paid const apiKeys = plan[planName]; apiKeys.forEach((apiKey, index) => { @@ -132,7 +133,9 @@ describe('#compileUsagePlanKeys()', () => { it('should throw if api key name does not match a usage plan', () => { awsCompileApigEvents.apiGatewayUsagePlanNames = ['default']; - awsCompileApigEvents.serverless.service.provider.apiKeys = [{ free: ['1234567890'] }]; + awsCompileApigEvents.serverless.service.provider.apiGateway = { + apiKeys: [{ free: ['1234567890'] }], + }; expect(() => awsCompileApigEvents.compileUsagePlanKeys()).to.throw( /has no usage plan defined/ );