Skip to content

Commit 651d96d

Browse files
committed
Add new method 'defineFunctionProperties' to 'ConfigSchemaHandler'
1 parent 61d8ee9 commit 651d96d

File tree

6 files changed

+105
-6
lines changed

6 files changed

+105
-6
lines changed

docs/providers/aws/guide/plugins.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,9 @@ Command names need to be unique. If we load two commands and both want to specif
417417

418418
If your plugin adds support for additional params in `serverless.yaml` file, you should also add validation rules to the Framework's schema. Otherwise, the Framework may place validation errors to command output about your params.
419419

420-
The Framework uses JSON-schema validation backed by [AJV](https://github.com/ajv-validator/ajv). You can extend [initial schema](/lib/configSchema/index.js) inside your plugin constuctor by using `defineCustomProperties`, `defineCustomEvent` or `defineProvider` helplers.
420+
The Framework uses JSON-schema validation backed by [AJV](https://github.com/ajv-validator/ajv). You can extend [initial schema](/lib/configSchema/index.js) inside your plugin constuctor by using `defineCustomProperties`, `defineFunctionEvent`, `defineFunctionProperties` or `defineProvider` helpers.
421421

422-
We'll walk though those heplers. You may also want to check out examples from [helpers tests](tests/fixtures/configSchemaExtensions/test-plugin.js)
422+
We'll walk though those helpers. You may also want to check out examples from [helpers tests](tests/fixtures/configSchemaExtensions/test-plugin.js)
423423

424424
#### `defineCustomProperties` helper
425425

@@ -510,6 +510,55 @@ This way, if user sets `anotherProp` by mistake to `some-string`, the Framework
510510
Serverless: Configuration error: functions.someFunc.events[0].yourPluginEvent.anotherProp should be number
511511
```
512512

513+
#### `defineFunctionProperties` helper
514+
515+
Let's say your plugin adds support to a new `someProperty` function property. To use this property, a user would need to have `serverless.yaml` file like this:
516+
517+
```
518+
// serverless.yaml
519+
520+
functions:
521+
someFunc:
522+
handler: handler.main
523+
someProperty: my-property-value
524+
```
525+
526+
In this case your plugin should add validation rules inside your plugin constructor. Otherwise, the Framework would display an error message saying that your property is not supported:
527+
528+
```
529+
ServerlessError: Configuration error:
530+
at 'functions.someFunc': unrecognized property 'someProperty'
531+
```
532+
533+
To fix this error and more importantly to provide validation rules for your property, modify your plugin constructor with code like this:
534+
535+
```javascript
536+
class NewEventPlugin {
537+
constructor(serverless) {
538+
this.serverless = serverless;
539+
540+
// Create schema for your properties. For reference use https://github.com/ajv-validator/ajv
541+
serverless.configSchemaHandler.defineFunctionProperties('providerName', {
542+
type: 'object',
543+
properties: {
544+
someProperty: { type: 'string' },
545+
anotherProperty: { type: 'number' },
546+
},
547+
required: ['someProperty'],
548+
additionalProperties: false,
549+
});
550+
}
551+
}
552+
```
553+
554+
This way, if user sets `anotherProperty` by mistake to `hello`, the Framework would display an error:
555+
556+
```
557+
ServerlessError: Configuration error at 'functions.someFunc.anotherProperty': should be number
558+
```
559+
560+
Note, however, that if the user sets `someProperty` to a number, it will just be treated as a string.
561+
513562
#### `defineProvider` helper
514563

515564
In case your plugin provides support for new provider, you would want to adjust validation schema. Here is example:

lib/classes/ConfigSchemaHandler/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,17 @@ class ConfigSchemaHandler {
216216
});
217217
}
218218

219+
defineFunctionProperties(providerName, configSchema) {
220+
if (this.serverless.service.provider.name !== providerName) {
221+
return;
222+
}
223+
224+
addPropertiesToSchema(
225+
this.schema.properties.functions.patternProperties[FUNCTION_NAME_PATTERN],
226+
configSchema
227+
);
228+
}
229+
219230
relaxProviderSchema() {
220231
// provider
221232
this.schema.properties.provider.additionalProperties = true;

lib/classes/ConfigSchemaHandler/index.test.js

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
const expect = require('chai').expect;
44
const runServerless = require('../../../test/utils/run-serverless');
55

6+
const FUNCTION_NAME_PATTERN = '^[a-zA-Z0-9-_]+$';
7+
68
describe('ConfigSchemaHandler', () => {
79
describe('#constructor', () => {
810
it('should freeze parts of schema for service', () => {
@@ -97,16 +99,40 @@ describe('ConfigSchemaHandler', () => {
9799

98100
expect(
99101
serverless.serverless.configSchemaHandler.schema.properties.functions.patternProperties[
100-
'^[a-zA-Z0-9-_]+$'
102+
FUNCTION_NAME_PATTERN
101103
].properties.events.items.anyOf[1]
102104
).to.deep.equal(expectedPieceOfSchema);
103105
return;
104106
});
105107
});
106108
});
107109

108-
describe('#defineCustomProperty', () => {
109-
it('should extend schema with defineCustomProperty method', () => {
110+
describe('#defineFunctionProperties', () => {
111+
it('should extend schema with defineFunctionProperties method', () => {
112+
return runServerless({
113+
fixture: 'configSchemaExtensions',
114+
cliArgs: ['info'],
115+
}).then(serverless => {
116+
const actualFunctionProperties =
117+
serverless.serverless.configSchemaHandler.schema.properties.functions.patternProperties[
118+
FUNCTION_NAME_PATTERN
119+
].properties;
120+
121+
expect(actualFunctionProperties).to.have.deep.property('someFunctionStringProp', {
122+
type: 'string',
123+
});
124+
125+
expect(actualFunctionProperties).to.have.deep.property('someRequiredFunctionNumberProp', {
126+
type: 'number',
127+
});
128+
129+
return;
130+
});
131+
});
132+
});
133+
134+
describe('#defineCustomProperties', () => {
135+
it('should extend schema with defineCustomProperties method', () => {
110136
return runServerless({
111137
fixture: 'configSchemaExtensions',
112138
cliArgs: ['info'],
@@ -163,7 +189,7 @@ describe('ConfigSchemaHandler', () => {
163189
const expectedHandlerPieceOfSchema = { type: 'string' };
164190
expect(
165191
serverless.serverless.configSchemaHandler.schema.properties.functions.patternProperties[
166-
'^[a-zA-Z0-9-_]+$'
192+
FUNCTION_NAME_PATTERN
167193
].properties.handler
168194
).to.deep.equal(expectedHandlerPieceOfSchema);
169195
return;

lib/configSchema.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ describe('#configSchema', () => {
7171
events: [],
7272
handler: 'someHandler',
7373
name: 'some-service-dev-someFunc',
74+
someRequiredFunctionNumberProp: 123,
7475
},
7576
},
7677
},

test/fixtures/configSchemaExtensions/serverless.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ custom:
1717

1818
functions:
1919
someFunction:
20+
someFunctionStringProp: function-string-prop
21+
someRequiredFunctionNumberProp: 321
2022
events:
2123
- someEvent:
2224
someRequiredStringProp: some string

test/fixtures/configSchemaExtensions/test-plugin.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ class TestPlugin {
2727
additionalProperties: false,
2828
});
2929

30+
serverless.configSchemaHandler.defineFunctionProperties('someProvider', {
31+
type: 'object',
32+
properties: {
33+
someFunctionStringProp: { type: 'string' },
34+
someRequiredFunctionNumberProp: { type: 'number' },
35+
},
36+
required: ['someRequiredFunctionNumberProp'],
37+
additionalProperties: false,
38+
});
39+
3040
serverless.configSchemaHandler.defineTopLevelProperty('top', {
3141
type: 'string',
3242
});

0 commit comments

Comments
 (0)