diff --git a/README.md b/README.md index 0a8f2fa8..017ba10a 100644 --- a/README.md +++ b/README.md @@ -968,6 +968,8 @@ provider: - myFirstKey - ${opt:stage}-myFirstKey - ${env:MY_API_KEY} # you can hide it in a serverless variable + - name: myKeyWithValue # object form — lets you set a specific key value + value: myApiKeyValue usagePlan: quota: limit: 5000 @@ -1004,6 +1006,8 @@ functions: - serverless-step-functions ``` +API key entries can be plain strings (the key name) or objects with a `name` and an optional `value` property. When `value` is provided, the API key is created with that specific value; otherwise AWS auto-generates the value. + Please note that those are the API keys names, not the actual values. Once you deploy your service, the value of those API keys will be auto generated by AWS and printed on the screen for you to use. The values can be concealed from the output with the --conceal deploy option. Clients connecting to this Rest API will then need to set any of these API keys values in the x-api-key header of their request. This is only necessary for functions where the private property is set to true. diff --git a/lib/deploy/events/apiGateway/apiKeys.js b/lib/deploy/events/apiGateway/apiKeys.js index feda16d7..74ea4132 100644 --- a/lib/deploy/events/apiGateway/apiKeys.js +++ b/lib/deploy/events/apiGateway/apiKeys.js @@ -15,24 +15,33 @@ module.exports = { _.forEach(apiKeys, (apiKey, i) => { const apiKeyNumber = i + 1; - if (typeof apiKey !== 'string') { - throw new this.serverless.classes.Error('API Keys must be strings'); + if (typeof apiKey !== 'string' && (typeof apiKey !== 'object' || !apiKey.name)) { + throw new this.serverless.classes.Error('API Keys must be strings or objects with a name property'); } + const apiKeyName = typeof apiKey === 'object' ? apiKey.name : apiKey; + const apiKeyValue = typeof apiKey === 'object' ? apiKey.value : undefined; + const apiKeyLogicalId = this.provider.naming .getApiKeyLogicalId(apiKeyNumber); + const properties = { + Enabled: true, + Name: apiKeyName, + StageKeys: [{ + RestApiId: { Ref: this.apiGatewayRestApiLogicalId }, + StageName: this.provider.getStage(), + }], + }; + + if (apiKeyValue !== undefined) { + properties.Value = apiKeyValue; + } + _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [apiKeyLogicalId]: { Type: 'AWS::ApiGateway::ApiKey', - Properties: { - Enabled: true, - Name: apiKey, - StageKeys: [{ - RestApiId: { Ref: this.apiGatewayRestApiLogicalId }, - StageName: this.provider.getStage(), - }], - }, + Properties: properties, DependsOn: this.apiGatewayDeploymentLogicalId, }, }); diff --git a/lib/deploy/events/apiGateway/apiKeys.test.js b/lib/deploy/events/apiGateway/apiKeys.test.js index da778587..3b975746 100644 --- a/lib/deploy/events/apiGateway/apiKeys.test.js +++ b/lib/deploy/events/apiGateway/apiKeys.test.js @@ -84,8 +84,39 @@ describe('#methods()', () => { expect(() => serverlessStepFunctions.compileApiKeys()).to.throw(Error); }); - it('throw error if an apiKey is not a string', () => { + it('throw error if an apiKey is not a string or object', () => { serverlessStepFunctions.serverless.service.provider.apiGateway.apiKeys = [2]; expect(() => serverlessStepFunctions.compileApiKeys()).to.throw(Error); }); + + it('should compile api key resource when apiKey is an object with name and value', () => { + serverlessStepFunctions.serverless.service.provider.apiGateway.apiKeys = [ + { name: 'my-api-key', value: 'my-secret-value' }, + ]; + return serverlessStepFunctions.compileApiKeys().then(() => { + const resource = serverlessStepFunctions.serverless.service.provider + .compiledCloudFormationTemplate.Resources[ + serverlessStepFunctions.provider.naming.getApiKeyLogicalId(1) + ]; + expect(resource.Type).to.equal('AWS::ApiGateway::ApiKey'); + expect(resource.Properties.Name).to.equal('my-api-key'); + expect(resource.Properties.Value).to.equal('my-secret-value'); + expect(resource.Properties.Enabled).to.equal(true); + }); + }); + + it('should compile api key resource when apiKey is an object with name only', () => { + serverlessStepFunctions.serverless.service.provider.apiGateway.apiKeys = [ + { name: 'my-api-key' }, + ]; + return serverlessStepFunctions.compileApiKeys().then(() => { + const resource = serverlessStepFunctions.serverless.service.provider + .compiledCloudFormationTemplate.Resources[ + serverlessStepFunctions.provider.naming.getApiKeyLogicalId(1) + ]; + expect(resource.Type).to.equal('AWS::ApiGateway::ApiKey'); + expect(resource.Properties.Name).to.equal('my-api-key'); + expect(resource.Properties.Value).to.equal(undefined); + }); + }); });