From e55f310f6481a6e1cceba1ac6799a0fdc27fa778 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 16:06:49 -0500 Subject: [PATCH 01/37] docs(repo): update intro to rulesets --- docs/getting-started/3-rulesets.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 86e195279..f0fe67e8d 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -2,15 +2,11 @@ Rulesets are collections of rules written in JSON, YAML, or [JavaScript](../guides/4-custom-rulesets.md#alternative-js-ruleset-format), which can be used to power powerful linting of other JSON or YAML files. Meta, we know! 😎 -These rules are taking parameters, and calling functions on certain parts of another YAML or JSON object being linted. +Ruleset files are often named `.spectral.yaml`, but that's not a requirement. -## Anatomy of a Ruleset +Rules take certain parameters and then call functions on parts of another YAML or JSON object being linted. -A ruleset is a JSON, YAML, or JavaScript file ([often the file will be called `.spectral.yaml`](../guides/2-cli.md#using-a-ruleset-file)), and there are two main parts. - -### Rules - -Rules might look a bit like this: +Here's what a rule might look like: ```yaml rules: @@ -25,15 +21,15 @@ rules: match: "^(\/|[a-z0-9-.]+|{[a-zA-Z0-9_]+})+$" ``` -Spectral has [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +The example above is a single rule that looks at all the `paths` to make sure they are kebab-case (lower-case and separated with hyphens). -Rules then target certain chunks of the JSON/YAML with the `given` keyword, which is a [JSONPath](http://jsonpath.com/) (actually, we use [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). +The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). -The example above adds a single rule that looks at the root level `tags` object's children to make sure they all have a `description` property. +The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. ### JSONPath Plus -As mentioned, spectral is using JSONPath Plus which expands on the original JSONPath specification to add some additional operators and makes explicit some behaviors the original did not spell out. +As mentioned, Spectral uses JSONPath Plus which expands on the original JSONPath specification to add some additional operators and makes explicit some behaviors the original did not spell out. Here are some convenient **additions or elaborations**: From 76a8a9a39b6a731fbb6471ca8aaf5289e7cacb81 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 16:42:57 -0500 Subject: [PATCH 02/37] docs(repo): expand on ruleset introduction --- docs/getting-started/3-rulesets.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index f0fe67e8d..3a3043d60 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -1,6 +1,6 @@ # Rulesets -Rulesets are collections of rules written in JSON, YAML, or [JavaScript](../guides/4-custom-rulesets.md#alternative-js-ruleset-format), which can be used to power powerful linting of other JSON or YAML files. Meta, we know! 😎 +Rulesets are collections of rules written in JSON, YAML, or [JavaScript](../guides/4-custom-rulesets.md#alternative-js-ruleset-format), which can be used to power powerful linting of other JSON or YAML files, such as OpenAPI or AsyncAPI descriptions. Meta, we know! 😎 Ruleset files are often named `.spectral.yaml`, but that's not a requirement. @@ -21,11 +21,14 @@ rules: match: "^(\/|[a-z0-9-.]+|{[a-zA-Z0-9_]+})+$" ``` -The example above is a single rule that looks at all the `paths` to make sure they are kebab-case (lower-case and separated with hyphens). +The example above is a single rule that can be used in an OpenAPI description. It will look at all the `paths` properties to make sure they are kebab-case (lower-case and separated with hyphens). -The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). +Breaking down each part of the rule: -The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +- `description` and `message` will help users quickly understand what the goal of the rule is +- `severity` will help define the importance of following the rule +- The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). +- The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. ### JSONPath Plus From cfd7647a82e3d11501b4a41258eea9ac05fe58d9 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 16:48:10 -0500 Subject: [PATCH 03/37] docs(repo): small update to intro --- docs/getting-started/3-rulesets.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 3a3043d60..b6fdc4208 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -6,7 +6,7 @@ Ruleset files are often named `.spectral.yaml`, but that's not a requirement. Rules take certain parameters and then call functions on parts of another YAML or JSON object being linted. -Here's what a rule might look like: +Here's what a ruleset with a single rule might look like: ```yaml rules: @@ -21,7 +21,7 @@ rules: match: "^(\/|[a-z0-9-.]+|{[a-zA-Z0-9_]+})+$" ``` -The example above is a single rule that can be used in an OpenAPI description. It will look at all the `paths` properties to make sure they are kebab-case (lower-case and separated with hyphens). +The example above is a rule that can be used in an OpenAPI description. It will look at all the `paths` properties to make sure they are kebab-case (lower-case and separated with hyphens). Breaking down each part of the rule: @@ -30,6 +30,15 @@ Breaking down each part of the rule: - The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). - The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +## Core Rulesets + +Spectral comes with two rulesets included: + +- `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) +- `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) + +You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). + ### JSONPath Plus As mentioned, Spectral uses JSONPath Plus which expands on the original JSONPath specification to add some additional operators and makes explicit some behaviors the original did not spell out. @@ -149,12 +158,3 @@ rules: ``` Custom formats can be registered via the [JS API](../guides/3-javascript.md), but the [CLI](../guides/2-cli.md) is limited to using the predefined formats. - -## Core Rulesets - -Spectral comes with two rulesets included: - -- `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) -- `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) - -You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). From 5dcd3a8e3bc2f4a964cce773a0606313b58710eb Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 16:53:14 -0500 Subject: [PATCH 04/37] docs(repo): add section for ruleset properties --- docs/getting-started/3-rulesets.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index b6fdc4208..aca3f5110 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -30,6 +30,14 @@ Breaking down each part of the rule: - The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). - The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +## Ruleset Properties + +There are three properties that can be used at the root level of a ruleset: + +- `rules` (required): An array of rules. +- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. +- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. + ## Core Rulesets Spectral comes with two rulesets included: From 90d8d806a4ec4d606e7465b735946267c7bf5ea3 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 17:06:26 -0500 Subject: [PATCH 05/37] docs(repo): remove JSONPath Plus section --- docs/getting-started/3-rulesets.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index aca3f5110..b338f73e0 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -47,29 +47,6 @@ Spectral comes with two rulesets included: You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). -### JSONPath Plus - -As mentioned, Spectral uses JSONPath Plus which expands on the original JSONPath specification to add some additional operators and makes explicit some behaviors the original did not spell out. - -Here are some convenient **additions or elaborations**: - -- `^` for grabbing the **parent** of a matching item -- `~` for grabbing **property names** of matching items (as array) -- **Type selectors** for obtaining: - - Basic JSON types: `@null()`, `@boolean()`, `@number()`, `@string()`, `@array()`, `@object()` - - `@integer()` - - The compound type `@scalar()` (which also accepts `undefined` and - non-finite numbers when querying JavaScript objects as well as all of the basic non-object/non-function types) - - `@other()` usable in conjunction with a user-defined `otherTypeCallback` - - Non-JSON types that can nevertheless be used when querying - non-JSON JavaScript objects (`@undefined()`, `@function()`, `@nonFinite()`) -- `@path`/`@parent`/`@property`/`@parentProperty`/`@root` **shorthand selectors** within filters -- **Escaping** - - `` ` `` for escaping remaining sequence - - `@['...']`/`?@['...']` syntax for escaping special characters within - property names in filters -- Documents `$..` (**getting all parent components**) - ### Extending Rulesets Rulesets can extend other rulesets using the `extends` property, allowing you to pull in other rulesets. From e9efc3488581f125f577dfe18ba3199bc085b2b8 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:11:47 -0500 Subject: [PATCH 06/37] docs(repo): add create a ruleset section to rulesets --- docs/getting-started/3-rulesets.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index b338f73e0..3b4720f07 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -6,6 +6,25 @@ Ruleset files are often named `.spectral.yaml`, but that's not a requirement. Rules take certain parameters and then call functions on parts of another YAML or JSON object being linted. +## Create a Ruleset + +The fastest way to create a ruleset is to use the `extends` property to leverage an existing ruleset. + +Spectral comes with two built-in rulesets: + +- `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) +- `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) + +To create a ruleset that extends both rulesets, in your terminal run: + +```bash +echo 'extends: ["spectral:oas", "spectral:asyncapi"]' > .spectral.yaml +``` + +The newly created ruleset file can then be used to lint any OpenAPI v2/v3 or AsyncAPI descriptions. + +## Write Your First Rule + Here's what a ruleset with a single rule might look like: ```yaml @@ -21,7 +40,7 @@ rules: match: "^(\/|[a-z0-9-.]+|{[a-zA-Z0-9_]+})+$" ``` -The example above is a rule that can be used in an OpenAPI description. It will look at all the `paths` properties to make sure they are kebab-case (lower-case and separated with hyphens). +The example above is a rule that can be used to validate an OpenAPI description. It will look at all the `paths` properties to make sure they are kebab-case (lower-case and separated with hyphens). Breaking down each part of the rule: @@ -30,6 +49,10 @@ Breaking down each part of the rule: - The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). - The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +## Next Steps + +For more information about creating Rulesets and Rules, see [Custom Rulesets](../guides/4-custom-rulesets.md). + ## Ruleset Properties There are three properties that can be used at the root level of a ruleset: From d6771a26f2c172fb37701e6b6e9fd7fa2f8a5993 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:20:35 -0500 Subject: [PATCH 07/37] docs(repo): remove core/custom functions section --- docs/guides/4-custom-rulesets.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 820f98882..835061efd 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -281,14 +281,6 @@ rules: function: truthy ``` -## Core Functions - -Several functions [are provided by default](../reference/functions.md) for your rules. - -## Custom Functions - -If none of the [core functions](../reference/functions.md) do what you want, you can [write your own custom functions](./5-custom-functions.md). - ## Aliases Targeting certain parts of an OpenAPI spec is powerful but it can become cumbersome to write and repeat complex JSONPath expressions across various rules. From 5b996385280bb2f3e98b0fba430b93ea3d1ab2f3 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:27:28 -0500 Subject: [PATCH 08/37] docs(repo): split up custom rulesets page --- docs/guides/4-custom-rulesets.md | 428 +------------------------------ docs/guides/4a-extends.md | 30 +++ docs/guides/4b-recommended.md | 41 +++ docs/guides/4c-aliases.md | 114 ++++++++ docs/guides/4d-overrides.md | 124 +++++++++ docs/guides/4e-js-rulesets.md | 110 ++++++++ toc.json | 35 ++- 7 files changed, 455 insertions(+), 427 deletions(-) create mode 100644 docs/guides/4a-extends.md create mode 100644 docs/guides/4b-recommended.md create mode 100644 docs/guides/4c-aliases.md create mode 100644 docs/guides/4d-overrides.md create mode 100644 docs/guides/4e-js-rulesets.md diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 835061efd..e75d75453 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -31,7 +31,7 @@ It has a specific syntax known as [JSONPath](https://goessner.net/articles/JsonP Both of them support all the main JSONPath functionality and a little bit more, but this syntax may differ slightly from other JSONPath implementations. Your `given` value can be a string containing any valid JSONPath expression, or an array of expressions to apply a rule to multiple parts of a document. -You can also consume your [aliases](#aliases) here if you have some defined. +You can also consume your [aliases](4c-aliases.md) here if you have some defined. Use the [JSONPath Online Evaluator](http://jsonpath.com/) to determine what `given` path you want. @@ -155,81 +155,10 @@ message: "{{value}} is greater than 0" message: "{{path}} cannot point at remote reference" ``` -## Modifying Rules - -When extending another ruleset, you can replace a rule defined in that ruleset by adding a new rule to your own ruleset with the same name. - -```yaml -extends: spectral:oas -rules: - tag-description: - description: Please provide a description for each tag. - given: $.tags[*] - then: - field: description - function: truthy -``` - -This provides a new description, but anything can be changed. - -If you're just looking to change the severity of the rule, there is a handy shortcut. - -### Changing Rule Severity - -Maybe you want to use the rules from the `spectral:oas` ruleset, but instead of `operation-success-response` triggering an error you'd like it to trigger a warning instead. - -```yaml -extends: spectral:oas -rules: - operation-success-response: warn -``` - -Available severity levels are `error`, `warn`, `info`, `hint`, and `off`. - -## Recommended or All - -Rules by default are considered "recommended" (equivalent to a rule having) `recommended: true` but they can also be marked as not recommended with `recommended: false`. This can help scenarios like rolling out rulesets across API landscapes with a lot of legacy APIs which might have a hard time following every rule immediately. A two-tier system for rules can be helpful here, to avoid requiring several rulesets for this basic use case. - -You can try this out with the core OpenAPI ruleset. If you simply extend the ruleset, by default you will only get the recommended rules. - -```yaml -extends: [[spectral:oas, recommended]] -``` - -Far more rules exist than just the recommended ones, there are various other rules which will help you create high-quality OpenAPI descriptions. - -```yaml -extends: [[spectral:oas, all]] -``` - -You can do this with your rulesets, and slide new rules in as not recommended for a while so that only the most interested active API designers/developers get them at first, then eventually roll them out to everyone if they are well received. - -### Disabling Rules - -This example shows the opposite of the "Enabling Specific Rules" example. Sometimes you might want to enable all rules by default, and disable a few. - -```yaml -extends: [[spectral:oas, all]] -rules: - operation-operationId-unique: off -``` - -The example above will run all of the rules defined in the `spectral:oas` ruleset (rather than the default behavior that runs only the recommended ones), with one exception - we turned `operation-operationId-unique` off. - -### Enabling Rules - -Sometimes you might want to apply a limited number of rules from another ruleset. To do this, use the `extends` property with `off` as the second argument. This will avoid running any rules from the extended ruleset as they will all be disabled. Then you can pick and choose which rules you would like to enable. - -```yaml -extends: [[spectral:oas, off]] -rules: - operation-operationId-unique: true -``` - -The example above will only run the rule `operation-operationId-unique` that we enabled since we passed `off` to disable all rules by default when extending the `spectral:oas` ruleset. - ## Parsing Options + + If you do not care about duplicate keys or invalid values (such as non-string mapping keys in YAML), you can tune their severity using the `parserOptions` setting. ```yaml @@ -280,354 +209,3 @@ rules: field: description function: truthy ``` - -## Aliases - -Targeting certain parts of an OpenAPI spec is powerful but it can become cumbersome to write and repeat complex JSONPath expressions across various rules. -Define aliases for commonly used JSONPath expressions on a global level which can then be reused across the ruleset. - -Aliases can be defined in an array of key-value pairs at the root level of the ruleset, or alternatively, within an override. -It's similar to `given`, with the notable difference being the possibility to distinguish between different formats. - -**Example** - -```yaml -aliases: - HeaderNames: - - "$..parameters.[?(@.in === 'header')].name" - Info: - - "$..info" - InfoDescription: - - "#Info.description" - InfoContact: - - "#Info.contact" - Paths: - - "$.paths[*]~" -``` - -If you deal with a variety of different specs, you may find the above approach insufficient, particularly when the shape of the document is notably different. -In such a case, you may want to consider using scoped aliases. - -```yaml -aliases: - SharedParameterObject: - description: an optional property describing the purpose of the alias - targets: - - formats: - - oas2 - given: - - $.parameters[*] - - formats: - - oas3 - given: - - $.components.parameters[*] -``` - -Now, if you referenced the `SharedParameterObject` alias, the chosen path would be determined based on the document you use. -For instance, if a given document matched OpenAPI 2.x, `$.parameters[*]` would be used as the JSONPath expression. - -Having a closer look at the example above, one may notice that it'd be still somewhat complicated to target _all_ Parameter Objects that a specific OpenAPI document may contain. To make it more feasible and avoid overly complex JSONPath expressions, `given` can be an array. - -```yaml -aliases: - PathItemObject: - - $.paths[*] - OperationObject: - - "#PathItem[get,put,post,delete,options,head,patch,trace]" - ParameterObject: - description: an optional property describing the purpose of the alias - targets: - - formats: - - oas2 - given: - - "#PathItemObject.parameters[*]" - - "#OperationObject.parameters[*]" - - $.parameters[*] - - formats: - - oas3 - given: - - "#PathItemObject.parameters[*]" - - "#OperationObject.parameters[*]" - - $.components.parameters[*] -``` - -Rulesets can then reference aliases in the [given](#given) keyword, either in full: `"given": "#Paths"`, or use it as a prefix for further JSONPath syntax, like dot notation: `"given": "#ParameterObject.name"`. - -Keep in mind that an alias has to be explicitly defined either at the root level or inside an override. This is to avoid ambiguity. - -```yaml -aliases: - Stoplight: - - "$..stoplight" -overrides: - - files: - - "*.yaml" - rules: - value-matches-stoplight: - message: Value must contain Stoplight - given: "#Stoplight" # valid because declared at the root - severity: error - then: - field: description - function: pattern - functionOptions: - match: Stoplight - - files: - - "**/*.json" - aliases: - Value: - - "$..value" - rules: - truthy-stoplight-property: - message: Value must contain Stoplight - given: "#Value" # valid because declared within the override block - severity: error - then: - function: truthy - - files: - - legacy/**/*.json - rules: - falsy-value: - given: "#Value" # invalid because undeclared both at the top-level and the override. Note that this could be technically resolvable for some JSON documents because the previous override block has the alias, but to spare some headaches, we demand an alias to be explicitly defined. - severity: error - then: - function: falsy -``` - -> This will be followed by our core rulesets providing a common set of aliases for OpenAPI and AsyncAPI so that our users don't have to do the work at all. If you have ideas about what kind of aliases could be useful leave your thoughts [here](https://roadmap.stoplight.io). - -## Overrides - -Previously Spectral supported exceptions, which were limited in their ability to target particular rules on specific files or parts of files, or change parts of a rule. Overrides is the much more powerful version of exceptions, with the ability to customize ruleset usage for different files and projects without having to duplicate any rules. - -Overrides can be used to apply rulesets on: - -- Particular formats `formats: [jsonSchemaDraft7]` -- Particular files/folders `files: ['schemas/**/*.draft7.json']` -- Particular elements of files `files: ['**#/components/schemas/Item']` -- Override particular rules - -**Example** - -```yaml -overrides: - formats: - - json-schema-draft7 - files: - - schemas/**/*.draft7.json - rules: - valid-number-validation: - given: - - $..exclusiveMinimum - - $..exclusiveMaximum - then: - function: schema - functionOptions: - type: number -``` - -To apply an override to particular elements of files, combine a glob for a filepath -with a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) after the anchor, i.e.: - -```yaml -overrides: - - files: - - "legacy/**/*.oas.json#/paths" - rules: - some-inherited-rule: "off" -``` - -JSON Pointers have a different syntax than JSON Paths used in the `given` component of a rule. -In JSON Pointers, path components are prefixed with a "/" and then concatenated to form the pointer. -Since "/" has a special meaning in JSON pointer, it must be encoded as "~1" when it appears in a component, and "~" must be encoded as "~0". - -You can test JSON Pointer expressions in the [JSON Query online evaluator](https://www.jsonquerytool.com/) by choosing "JSONPointer" as the Transform. - -```yaml -overrides: - - files: - - "legacy/**/*.oas.json#/paths/~1Pets~1{petId}/get/parameters/0" - rules: - some-inherited-rule: "off" -``` - -In the event of multiple matches, the order of definition takes place, with the last one having the higher priority. - -### Caveats - -Please bear in mind that overrides are only applied to the _root_ documents. If your documents have any external dependencies, i.e. $refs, the overrides won't apply. - -**Example:** - -Given the following 2 YAML documents: - -```yaml -# my-document.yaml -openapi: "3.1.0" -paths: {} -components: - schemas: - User: - $ref: "./User.yaml" -``` - -```yaml -# User.yaml -title: "" -type: object -properties: - id: - type: string -required: - - id -``` - -And the ruleset below: - -```json -{ - "rules": { - "empty-title-property": { - "message": "Title must not be empty", - "given": "$..title", - "then": { - "function": "truthy" - } - } - }, - "overrides": [ - { - "files": ["User.yaml"], - "rules": { - "empty-title-property": "off" - } - } - ] -} -``` - -Running `spectral lint my-document.yaml` will result in the following output: - -``` -/project/User.yaml - 1:8 warning empty-title-property Title must not be empty title - -✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints) -``` - -While executing `spectral lint User.yaml` will output: - -``` -No results with a severity of 'error' or higher found! -``` - -## Alternative JS Ruleset Format - -Spectral v6.0 added support for a JavaScript ruleset format, similar to the JSON and YAML formats. - -This has a few benefits: it lets you explicitly load formats or rulesets to get control over versioning, you can load common functions from popular JS libraries, and in general feels a lot more welcoming to developers experienced with JavaScript, especially when it comes to working with custom functions. - -**Example** - -To create a JavaScript ruleset, the first step is creating a folder. In your terminal, run the following commands: - -``` -mkdir style-guide -cd style-guide -``` - -Next, install two dependencies using [npm](https://www.npmjs.com/): - -``` -npm install --save @stoplight/spectral-functions -npm install --save @stoplight/spectral-formats -``` - -Installing these packages is not required for creating a JavaScript ruleset, but we'll use them in our example to create some common rules used with Spectral and to target a specific OpenAPI format. - -Next, let's create a JavaScript file to hold our ruleset: - -``` -touch spectral.js -``` - -And inside the file, let's create a couple rules: - -```js -import { truthy, undefined as pattern, schema } from "@stoplight/spectral-functions"; -import { oas3 } from "@stoplight/spectral-formats"; - -export default { - rules: { - "api-home-get": { - description: "APIs root path (`/`) MUST have a GET operation.", - message: "Otherwise people won't know how to get it.", - given: "$.paths[/]", - then: { - field: "get", - function: truthy, - }, - severity: "warn", - }, - - // Author: Phil Sturgeon (https://github.com/philsturgeon) - "no-numeric-ids": { - description: "Avoid exposing IDs as an integer, UUIDs are preferred.", - given: '$.paths..parameters[*].[?(@property === "name" && (@ === "id" || @.match(/(_id|Id)$/)))]^.schema', - then: { - function: schema, - functionOptions: { - schema: { - type: "object", - not: { - properties: { - type: { - const: "integer", - }, - }, - }, - properties: { - format: { - const: "uuid", - }, - }, - }, - }, - }, - severity: "error", - }, - - // Author: Nauman Ali (https://github.com/naumanali-stoplight) - "no-global-versioning": { - description: "Using global versions just forces all your clients to do a lot more work for each upgrade. Please consider using API Evolution instead.", - message: "Server URL should not contain global versions", - given: "$.servers[*].url", - then: { - function: pattern, - functionOptions: { - notMatch: "/v[1-9]", - }, - }, - formats: [oas3], - severity: "warn", - }, - }, -}; -``` - -For those of you using custom functions, the keywords `functions` & `functionOptions` have been removed, as they were designed to help Spectral find your functions. Now functions are passed as a variable, instead of using a string that contains the name like the JSON/YAML formats. - -This code example should look fairly familiar for anyone who has used the JSON or YAML formats. The next steps for using this ruleset would be publishing it as an npm package, and then installing that package as part of your API project and referencing in your Spectral ruleset as: - -``` -extends: ["@your-js-ruleset"] -``` - -Or using unpkg: - -``` -extends: - - https://unpkg.com/@your-js-ruleset -``` - -For a more detailed example of creating a JavaScript ruleset and publishing it to npm, check out [Distribute Spectral Style Guides with npm](https://apisyouwonthate.com/blog/distribute-spectral-style-guides-with-npm) at APIs You Won't Hate. diff --git a/docs/guides/4a-extends.md b/docs/guides/4a-extends.md new file mode 100644 index 000000000..7558d65c9 --- /dev/null +++ b/docs/guides/4a-extends.md @@ -0,0 +1,30 @@ +## Modifying Rules + +When extending another ruleset, you can replace a rule defined in that ruleset by adding a new rule to your own ruleset with the same name. + +```yaml +extends: spectral:oas +rules: + tag-description: + description: Please provide a description for each tag. + given: $.tags[*] + then: + field: description + function: truthy +``` + +This provides a new description, but anything can be changed. + +If you're just looking to change the severity of the rule, there is a handy shortcut. + +### Changing Rule Severity + +Maybe you want to use the rules from the `spectral:oas` ruleset, but instead of `operation-success-response` triggering an error you'd like it to trigger a warning instead. + +```yaml +extends: spectral:oas +rules: + operation-success-response: warn +``` + +Available severity levels are `error`, `warn`, `info`, `hint`, and `off`. diff --git a/docs/guides/4b-recommended.md b/docs/guides/4b-recommended.md new file mode 100644 index 000000000..e579d02de --- /dev/null +++ b/docs/guides/4b-recommended.md @@ -0,0 +1,41 @@ +## Recommended or All + +Rules by default are considered "recommended" (equivalent to a rule having) `recommended: true` but they can also be marked as not recommended with `recommended: false`. This can help scenarios like rolling out rulesets across API landscapes with a lot of legacy APIs which might have a hard time following every rule immediately. A two-tier system for rules can be helpful here, to avoid requiring several rulesets for this basic use case. + +You can try this out with the core OpenAPI ruleset. If you simply extend the ruleset, by default you will only get the recommended rules. + +```yaml +extends: [[spectral:oas, recommended]] +``` + +Far more rules exist than just the recommended ones, there are various other rules which will help you create high-quality OpenAPI descriptions. + +```yaml +extends: [[spectral:oas, all]] +``` + +You can do this with your rulesets, and slide new rules in as not recommended for a while so that only the most interested active API designers/developers get them at first, then eventually roll them out to everyone if they are well received. + +### Disabling Rules + +This example shows the opposite of the "Enabling Specific Rules" example. Sometimes you might want to enable all rules by default, and disable a few. + +```yaml +extends: [[spectral:oas, all]] +rules: + operation-operationId-unique: off +``` + +The example above will run all of the rules defined in the `spectral:oas` ruleset (rather than the default behavior that runs only the recommended ones), with one exception - we turned `operation-operationId-unique` off. + +### Enabling Rules + +Sometimes you might want to apply a limited number of rules from another ruleset. To do this, use the `extends` property with `off` as the second argument. This will avoid running any rules from the extended ruleset as they will all be disabled. Then you can pick and choose which rules you would like to enable. + +```yaml +extends: [[spectral:oas, off]] +rules: + operation-operationId-unique: true +``` + +The example above will only run the rule `operation-operationId-unique` that we enabled since we passed `off` to disable all rules by default when extending the `spectral:oas` ruleset. diff --git a/docs/guides/4c-aliases.md b/docs/guides/4c-aliases.md new file mode 100644 index 000000000..4ae05f52e --- /dev/null +++ b/docs/guides/4c-aliases.md @@ -0,0 +1,114 @@ +## Aliases + +Targeting certain parts of an OpenAPI spec is powerful but it can become cumbersome to write and repeat complex JSONPath expressions across various rules. +Define aliases for commonly used JSONPath expressions on a global level which can then be reused across the ruleset. + +Aliases can be defined in an array of key-value pairs at the root level of the ruleset, or alternatively, within an override. +It's similar to `given`, with the notable difference being the possibility to distinguish between different formats. + +**Example** + +```yaml +aliases: + HeaderNames: + - "$..parameters.[?(@.in === 'header')].name" + Info: + - "$..info" + InfoDescription: + - "#Info.description" + InfoContact: + - "#Info.contact" + Paths: + - "$.paths[*]~" +``` + +If you deal with a variety of different specs, you may find the above approach insufficient, particularly when the shape of the document is notably different. +In such a case, you may want to consider using scoped aliases. + +```yaml +aliases: + SharedParameterObject: + description: an optional property describing the purpose of the alias + targets: + - formats: + - oas2 + given: + - $.parameters[*] + - formats: + - oas3 + given: + - $.components.parameters[*] +``` + +Now, if you referenced the `SharedParameterObject` alias, the chosen path would be determined based on the document you use. +For instance, if a given document matched OpenAPI 2.x, `$.parameters[*]` would be used as the JSONPath expression. + +Having a closer look at the example above, one may notice that it'd be still somewhat complicated to target _all_ Parameter Objects that a specific OpenAPI document may contain. To make it more feasible and avoid overly complex JSONPath expressions, `given` can be an array. + +```yaml +aliases: + PathItemObject: + - $.paths[*] + OperationObject: + - "#PathItem[get,put,post,delete,options,head,patch,trace]" + ParameterObject: + description: an optional property describing the purpose of the alias + targets: + - formats: + - oas2 + given: + - "#PathItemObject.parameters[*]" + - "#OperationObject.parameters[*]" + - $.parameters[*] + - formats: + - oas3 + given: + - "#PathItemObject.parameters[*]" + - "#OperationObject.parameters[*]" + - $.components.parameters[*] +``` + +Rulesets can then reference aliases in the [given](#given) keyword, either in full: `"given": "#Paths"`, or use it as a prefix for further JSONPath syntax, like dot notation: `"given": "#ParameterObject.name"`. + +Keep in mind that an alias has to be explicitly defined either at the root level or inside an override. This is to avoid ambiguity. + +```yaml +aliases: + Stoplight: + - "$..stoplight" +overrides: + - files: + - "*.yaml" + rules: + value-matches-stoplight: + message: Value must contain Stoplight + given: "#Stoplight" # valid because declared at the root + severity: error + then: + field: description + function: pattern + functionOptions: + match: Stoplight + - files: + - "**/*.json" + aliases: + Value: + - "$..value" + rules: + truthy-stoplight-property: + message: Value must contain Stoplight + given: "#Value" # valid because declared within the override block + severity: error + then: + function: truthy + - files: + - legacy/**/*.json + rules: + falsy-value: + given: "#Value" # invalid because undeclared both at the top-level and the override. Note that this could be technically resolvable for some JSON documents because the previous override block has the alias, but to spare some headaches, we demand an alias to be explicitly defined. + severity: error + then: + function: falsy +``` + +> This will be followed by our core rulesets providing a common set of aliases for OpenAPI and AsyncAPI so that our users don't have to do the work at all. If you have ideas about what kind of aliases could be useful leave your thoughts [here](https://roadmap.stoplight.io). diff --git a/docs/guides/4d-overrides.md b/docs/guides/4d-overrides.md new file mode 100644 index 000000000..01b61020a --- /dev/null +++ b/docs/guides/4d-overrides.md @@ -0,0 +1,124 @@ +## Overrides + +Previously Spectral supported exceptions, which were limited in their ability to target particular rules on specific files or parts of files, or change parts of a rule. Overrides is the much more powerful version of exceptions, with the ability to customize ruleset usage for different files and projects without having to duplicate any rules. + +Overrides can be used to apply rulesets on: + +- Particular formats `formats: [jsonSchemaDraft7]` +- Particular files/folders `files: ['schemas/**/*.draft7.json']` +- Particular elements of files `files: ['**#/components/schemas/Item']` +- Override particular rules + +**Example** + +```yaml +overrides: + formats: + - json-schema-draft7 + files: + - schemas/**/*.draft7.json + rules: + valid-number-validation: + given: + - $..exclusiveMinimum + - $..exclusiveMaximum + then: + function: schema + functionOptions: + type: number +``` + +To apply an override to particular elements of files, combine a glob for a filepath +with a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) after the anchor, i.e.: + +```yaml +overrides: + - files: + - "legacy/**/*.oas.json#/paths" + rules: + some-inherited-rule: "off" +``` + +JSON Pointers have a different syntax than JSON Paths used in the `given` component of a rule. +In JSON Pointers, path components are prefixed with a "/" and then concatenated to form the pointer. +Since "/" has a special meaning in JSON pointer, it must be encoded as "~1" when it appears in a component, and "~" must be encoded as "~0". + +You can test JSON Pointer expressions in the [JSON Query online evaluator](https://www.jsonquerytool.com/) by choosing "JSONPointer" as the Transform. + +```yaml +overrides: + - files: + - "legacy/**/*.oas.json#/paths/~1Pets~1{petId}/get/parameters/0" + rules: + some-inherited-rule: "off" +``` + +In the event of multiple matches, the order of definition takes place, with the last one having the higher priority. + +### Caveats + +Please bear in mind that overrides are only applied to the _root_ documents. If your documents have any external dependencies, i.e. $refs, the overrides won't apply. + +**Example:** + +Given the following 2 YAML documents: + +```yaml +# my-document.yaml +openapi: "3.1.0" +paths: {} +components: + schemas: + User: + $ref: "./User.yaml" +``` + +```yaml +# User.yaml +title: "" +type: object +properties: + id: + type: string +required: + - id +``` + +And the ruleset below: + +```json +{ + "rules": { + "empty-title-property": { + "message": "Title must not be empty", + "given": "$..title", + "then": { + "function": "truthy" + } + } + }, + "overrides": [ + { + "files": ["User.yaml"], + "rules": { + "empty-title-property": "off" + } + } + ] +} +``` + +Running `spectral lint my-document.yaml` will result in the following output: + +``` +/project/User.yaml + 1:8 warning empty-title-property Title must not be empty title + +✖ 1 problem (0 errors, 1 warning, 0 infos, 0 hints) +``` + +While executing `spectral lint User.yaml` will output: + +``` +No results with a severity of 'error' or higher found! +``` diff --git a/docs/guides/4e-js-rulesets.md b/docs/guides/4e-js-rulesets.md new file mode 100644 index 000000000..baa597ee7 --- /dev/null +++ b/docs/guides/4e-js-rulesets.md @@ -0,0 +1,110 @@ +## JavaScript Ruleset Format + +Spectral v6.0 added support for a JavaScript ruleset format, similar to the JSON and YAML formats. + +This has a few benefits: it lets you explicitly load formats or rulesets to get control over versioning, you can load common functions from popular JS libraries, and in general feels a lot more welcoming to developers experienced with JavaScript, especially when it comes to working with custom functions. + +**Example** + +To create a JavaScript ruleset, the first step is creating a folder. In your terminal, run the following commands: + +``` +mkdir style-guide +cd style-guide +``` + +Next, install two dependencies using [npm](https://www.npmjs.com/): + +``` +npm install --save @stoplight/spectral-functions +npm install --save @stoplight/spectral-formats +``` + +Installing these packages is not required for creating a JavaScript ruleset, but we'll use them in our example to create some common rules used with Spectral and to target a specific OpenAPI format. + +Next, let's create a JavaScript file to hold our ruleset: + +``` +touch spectral.js +``` + +And inside the file, let's create a couple rules: + +```js +import { truthy, undefined as pattern, schema } from "@stoplight/spectral-functions"; +import { oas3 } from "@stoplight/spectral-formats"; + +export default { + rules: { + "api-home-get": { + description: "APIs root path (`/`) MUST have a GET operation.", + message: "Otherwise people won't know how to get it.", + given: "$.paths[/]", + then: { + field: "get", + function: truthy, + }, + severity: "warn", + }, + + // Author: Phil Sturgeon (https://github.com/philsturgeon) + "no-numeric-ids": { + description: "Avoid exposing IDs as an integer, UUIDs are preferred.", + given: '$.paths..parameters[*].[?(@property === "name" && (@ === "id" || @.match(/(_id|Id)$/)))]^.schema', + then: { + function: schema, + functionOptions: { + schema: { + type: "object", + not: { + properties: { + type: { + const: "integer", + }, + }, + }, + properties: { + format: { + const: "uuid", + }, + }, + }, + }, + }, + severity: "error", + }, + + // Author: Nauman Ali (https://github.com/naumanali-stoplight) + "no-global-versioning": { + description: "Using global versions just forces all your clients to do a lot more work for each upgrade. Please consider using API Evolution instead.", + message: "Server URL should not contain global versions", + given: "$.servers[*].url", + then: { + function: pattern, + functionOptions: { + notMatch: "/v[1-9]", + }, + }, + formats: [oas3], + severity: "warn", + }, + }, +}; +``` + +For those of you using custom functions, the keywords `functions` & `functionOptions` have been removed, as they were designed to help Spectral find your functions. Now functions are passed as a variable, instead of using a string that contains the name like the JSON/YAML formats. + +This code example should look fairly familiar for anyone who has used the JSON or YAML formats. The next steps for using this ruleset would be publishing it as an npm package, and then installing that package as part of your API project and referencing in your Spectral ruleset as: + +``` +extends: ["@your-js-ruleset"] +``` + +Or using unpkg: + +``` +extends: + - https://unpkg.com/@your-js-ruleset +``` + +For a more detailed example of creating a JavaScript ruleset and publishing it to npm, check out [Distribute Spectral Style Guides with npm](https://apisyouwonthate.com/blog/distribute-spectral-style-guides-with-npm) at APIs You Won't Hate. diff --git a/toc.json b/toc.json index b65c935e9..d3a015f0c 100644 --- a/toc.json +++ b/toc.json @@ -54,9 +54,40 @@ "uri": "/docs/guides/3-javascript.md" }, { - "type": "item", + "type": "group", "title": "Custom Rulesets", - "uri": "/docs/guides/4-custom-rulesets.md" + "items": [ + { + "type": "item", + "title": "Overview", + "uri": "/docs/guides/4-custom-rulesets.md" + }, + { + "type": "item", + "title": "Extends", + "uri": "/docs/guides/4a-extends.md" + }, + { + "type": "item", + "title": "Recommended", + "uri": "/docs/guides/4b-recommended.md" + }, + { + "type": "item", + "title": "Aliases", + "uri": "/docs/guides/4c-aliases.md" + }, + { + "type": "item", + "title": "Overrides", + "uri": "/docs/guides/4d-overrides.md" + }, + { + "type": "item", + "title": "JavaScript Ruleset Format", + "uri": "/docs/guides/4e-js-rulesets.md" + } + ] }, { "type": "item", From c890a6b38bf0f20104c8d6a3c016b666fae4a883 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:38:52 -0500 Subject: [PATCH 09/37] docs(repo): move formats to custom rulesets --- docs/getting-started/3-rulesets.md | 78 ------------------------------ docs/guides/4-custom-rulesets.md | 78 ++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 3b4720f07..468bfce3e 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -88,81 +88,3 @@ extends: ``` The `extends` keyword can be combined with extra rules in order to extend and override rulesets. Learn more about that in [custom rulesets](../guides/4-custom-rulesets.md). - -### Formats - -Formats are an optional way to specify which API description formats a rule, or ruleset, is applicable to. Currently Spectral supports these formats: - -- `aas2` (AsyncAPI v2.x) -- `aas2_0` (AsyncAPI v2.0.0) -- `aas2_1` (AsyncAPI v2.1.0) -- `aas2_2` (AsyncAPI v2.2.0) -- `aas2_3` (AsyncAPI v2.3.0) -- `aas2_4` (AsyncAPI v2.4.0) -- `aas2_5` (AsyncAPI v2.5.0) -- `oas2` (OpenAPI v2.0) -- `oas3` (OpenAPI v3.x) -- `oas3_0` (OpenAPI v3.0.x) -- `oas3_1` (OpenAPI v3.1.x) -- `json-schema` (`$schema` says this is some JSON Schema draft) -- `json-schema-loose` (looks like JSON Schema, but no `$schema` found) -- `json-schema-draft4` (`$schema` says this is JSON Schema Draft 04) -- `json-schema-draft6` (`$schema` says this is JSON Schema Draft 06) -- `json-schema-draft7` (`$schema` says this is JSON Schema Draft 07) -- `json-schema-2019-09` (`$schema` says this is JSON Schema 2019-09) -- `json-schema-2020-12` (`$schema` says this is JSON Schema 2020-12) - -Specifying the format is optional, so you can completely ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. If you'd like to use one ruleset for multiple formats, the `formats` key is here to help. - -```yaml -rules: - oas3-api-servers: - description: "OpenAPI `servers` must be present and non-empty array." - formats: ["oas3"] - given: "$" - then: - field: servers - function: schema - functionOptions: - schema: - items: - type: object - minItems: 1 - type: array -``` - -Specifying the format is optional, so you can completely ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. - -Formats can be specified at the ruleset level: - -```yaml -formats: ["oas3"] -rules: - oas3-api-servers: - description: "OpenAPI `servers` must be present and non-empty array." - given: "$" - then: - # ... -``` - -Now all the rules in this ruleset will only be applied if the specified format is detected. - -If you'd like to use one ruleset for multiple formats but some rules only apply to one format, you can place the `formats` keyword at the rule level instead: - -```yaml -rules: - oas3-api-servers: - description: "OpenAPI `servers` must be present and non-empty array." - formats: ["oas3"] - given: "$" - then: - # ... - oas2-hosts: - description: "OpenAPI `servers` must be present and non-empty array." - formats: ["oas2"] - given: "$" - then: - # ... -``` - -Custom formats can be registered via the [JS API](../guides/3-javascript.md), but the [CLI](../guides/2-cli.md) is limited to using the predefined formats. diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index e75d75453..a19f6f1da 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -209,3 +209,81 @@ rules: field: description function: truthy ``` + +## Formats + +Formats are an optional way to specify which API description formats a rule, or ruleset, is applicable to. Currently Spectral supports these formats: + +- `aas2` (AsyncAPI v2.x) +- `aas2_0` (AsyncAPI v2.0.0) +- `aas2_1` (AsyncAPI v2.1.0) +- `aas2_2` (AsyncAPI v2.2.0) +- `aas2_3` (AsyncAPI v2.3.0) +- `aas2_4` (AsyncAPI v2.4.0) +- `aas2_5` (AsyncAPI v2.5.0) +- `oas2` (OpenAPI v2.0) +- `oas3` (OpenAPI v3.x) +- `oas3_0` (OpenAPI v3.0.x) +- `oas3_1` (OpenAPI v3.1.x) +- `json-schema` (`$schema` says this is some JSON Schema draft) +- `json-schema-loose` (looks like JSON Schema, but no `$schema` found) +- `json-schema-draft4` (`$schema` says this is JSON Schema Draft 04) +- `json-schema-draft6` (`$schema` says this is JSON Schema Draft 06) +- `json-schema-draft7` (`$schema` says this is JSON Schema Draft 07) +- `json-schema-2019-09` (`$schema` says this is JSON Schema 2019-09) +- `json-schema-2020-12` (`$schema` says this is JSON Schema 2020-12) + +Specifying the format is optional, so you can completely ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. If you'd like to use one ruleset for multiple formats, the `formats` key is here to help. + +```yaml +rules: + oas3-api-servers: + description: "OpenAPI `servers` must be present and non-empty array." + formats: ["oas3"] + given: "$" + then: + field: servers + function: schema + functionOptions: + schema: + items: + type: object + minItems: 1 + type: array +``` + +Specifying the format is optional, so you can completely ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. + +Formats can be specified at the ruleset level: + +```yaml +formats: ["oas3"] +rules: + oas3-api-servers: + description: "OpenAPI `servers` must be present and non-empty array." + given: "$" + then: + # ... +``` + +Now all the rules in this ruleset will only be applied if the specified format is detected. + +If you'd like to use one ruleset for multiple formats but some rules only apply to one format, you can place the `formats` keyword at the rule level instead: + +```yaml +rules: + oas3-api-servers: + description: "OpenAPI `servers` must be present and non-empty array." + formats: ["oas3"] + given: "$" + then: + # ... + oas2-hosts: + description: "OpenAPI `servers` must be present and non-empty array." + formats: ["oas2"] + given: "$" + then: + # ... +``` + +Custom formats can be registered via the [JS API](../guides/3-javascript.md), but the [CLI](../guides/2-cli.md) is limited to using the predefined formats. From 0baa4258ec9887700f4d393e20c0f02f242feeb7 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:41:46 -0500 Subject: [PATCH 10/37] docs(repo): move ruleset properties to custom rulesets --- docs/getting-started/3-rulesets.md | 8 -------- docs/guides/4-custom-rulesets.md | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 468bfce3e..1b99cf9a3 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -53,14 +53,6 @@ Breaking down each part of the rule: For more information about creating Rulesets and Rules, see [Custom Rulesets](../guides/4-custom-rulesets.md). -## Ruleset Properties - -There are three properties that can be used at the root level of a ruleset: - -- `rules` (required): An array of rules. -- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. -- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. - ## Core Rulesets Spectral comes with two rulesets included: diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index a19f6f1da..97629b302 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -6,6 +6,15 @@ If you'd like to make sure your APIs are consistent and high quality even before Or you can create a custom ruleset to make sure your Jekyll or Gatsby custom data is valid. Whatever you want to do, to start with you'll need to create some rules. +## Ruleset Properties + +There are three properties that can be used at the root level of a ruleset: + +- `rules` (required): An array of rules. +- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. +- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. +- `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. + ## Adding Rules Add your own rules under the `rules` property in your `.spectral.yml`, or another ruleset file. From 8783457657c1e6832dd4aa79e0448e8bb0b762b5 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:44:16 -0500 Subject: [PATCH 11/37] docs(repo): move extending rulesets section --- docs/getting-started/3-rulesets.md | 19 ------------------- docs/guides/4a-extends.md | 23 +++++++++++++++++++++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 1b99cf9a3..04da63375 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -61,22 +61,3 @@ Spectral comes with two rulesets included: - `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). - -### Extending Rulesets - -Rulesets can extend other rulesets using the `extends` property, allowing you to pull in other rulesets. - -```yaml -extends: spectral:oas -``` - -Extends can reference any [distributed ruleset](../guides/7-sharing-rulesets.md). It can be a single string, or an array of strings, and can contain either local file paths, URLs, or even npm modules. - -```yaml -extends: - - ./config/spectral.json - - https://example.org/api/style.yaml - - some-npm-module # note that this would be treated as any other npm package, therefore it has to be placed under node_modules and have a valid package.json. -``` - -The `extends` keyword can be combined with extra rules in order to extend and override rulesets. Learn more about that in [custom rulesets](../guides/4-custom-rulesets.md). diff --git a/docs/guides/4a-extends.md b/docs/guides/4a-extends.md index 7558d65c9..2b091dce1 100644 --- a/docs/guides/4a-extends.md +++ b/docs/guides/4a-extends.md @@ -1,4 +1,23 @@ -## Modifying Rules +# Extending Rulesets + +Rulesets can extend other rulesets using the `extends` property, allowing you to pull in other rulesets. + +```yaml +extends: spectral:oas +``` + +Extends can reference any [distributed ruleset](../guides/7-sharing-rulesets.md). It can be a single string, or an array of strings, and can contain either local file paths, URLs, or even npm modules. + +```yaml +extends: + - ./config/spectral.json + - https://example.org/api/style.yaml + - some-npm-module # note that this would be treated as any other npm package, therefore it has to be placed under node_modules and have a valid package.json. +``` + +The `extends` keyword can be combined with extra rules in order to extend and override rulesets. Learn more about that in [custom rulesets](../guides/4-custom-rulesets.md). + +## Modify Rules When extending another ruleset, you can replace a rule defined in that ruleset by adding a new rule to your own ruleset with the same name. @@ -17,7 +36,7 @@ This provides a new description, but anything can be changed. If you're just looking to change the severity of the rule, there is a handy shortcut. -### Changing Rule Severity +## Change Rule Severity Maybe you want to use the rules from the `spectral:oas` ruleset, but instead of `operation-success-response` triggering an error you'd like it to trigger a warning instead. From ae825db23b7a3e368eae6208db9de89f73b093cc Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 14 Oct 2022 18:45:05 -0500 Subject: [PATCH 12/37] docs(repo): move core rulesets section --- docs/getting-started/3-rulesets.md | 9 --------- docs/guides/4-custom-rulesets.md | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 04da63375..8cf1eb35c 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -52,12 +52,3 @@ Breaking down each part of the rule: ## Next Steps For more information about creating Rulesets and Rules, see [Custom Rulesets](../guides/4-custom-rulesets.md). - -## Core Rulesets - -Spectral comes with two rulesets included: - -- `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) -- `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) - -You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 97629b302..792428554 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -296,3 +296,12 @@ rules: ``` Custom formats can be registered via the [JS API](../guides/3-javascript.md), but the [CLI](../guides/2-cli.md) is limited to using the predefined formats. + +## Core Rulesets + +Spectral comes with two rulesets included: + +- `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) +- `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) + +You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). From 8de6fa9b6be3d903ff8a61b0b284cf9491ebde7b Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Mon, 17 Oct 2022 09:36:25 -0500 Subject: [PATCH 13/37] docs(repo): small updates to custom rulesets overview --- docs/guides/4-custom-rulesets.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 792428554..af80555a4 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -8,16 +8,16 @@ Or you can create a custom ruleset to make sure your Jekyll or Gatsby custom dat ## Ruleset Properties -There are three properties that can be used at the root level of a ruleset: +There are four properties that can be used at the root level of a ruleset: - `rules` (required): An array of rules. - `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. - `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. - `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. -## Adding Rules +## Add Rules -Add your own rules under the `rules` property in your `.spectral.yml`, or another ruleset file. +Add your own rules under the `rules` property in your ruleset file. ```yaml rules: @@ -32,6 +32,8 @@ rules: Spectral has [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +## Rules Properties + ### Given The `given` property is conceptually quite like a selector in CSS, in that it picks the part of the document to apply rules to. From 6a284b046d62deea2d36473b85a711b012e9d190 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 13:21:56 -0500 Subject: [PATCH 14/37] docs(repo): update resolved rule example --- docs/guides/4-custom-rulesets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index af80555a4..95b32b7db 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -71,7 +71,7 @@ Here's an example of a rule that can access `$ref` values: rules: my-rule-name: description: Parameters must be references - given: $.paths.[*][get,post,put,delete,options] + given: $.paths[*][get,post,put,delete,options] severity: error resolved: false then: From 54c834415953ed53855a9534b3658f6cbb9920d4 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 13:37:30 -0500 Subject: [PATCH 15/37] docs(repo): add lint instruction to rulesets --- docs/getting-started/3-rulesets.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 8cf1eb35c..e813166ad 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -21,7 +21,11 @@ To create a ruleset that extends both rulesets, in your terminal run: echo 'extends: ["spectral:oas", "spectral:asyncapi"]' > .spectral.yaml ``` -The newly created ruleset file can then be used to lint any OpenAPI v2/v3 or AsyncAPI descriptions. +The newly created ruleset file can then be used to lint any OpenAPI v2/v3 or AsyncAPI descriptions by using the `spectral lint` command: + +```bash +spectral lint myapifile.yaml +``` ## Write Your First Rule From b34b79fe2c866c79316240abf3e7a007fa399ec1 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 13:40:42 -0500 Subject: [PATCH 16/37] docs(repo): add link to other rulesets --- docs/getting-started/3-rulesets.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index e813166ad..15c165082 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -56,3 +56,5 @@ Breaking down each part of the rule: ## Next Steps For more information about creating Rulesets and Rules, see [Custom Rulesets](../guides/4-custom-rulesets.md). + +For more examples of existing rulesets you can use, see [Real-World Rulesets](../../README.md#🌎-real-world-rulesets) in our README. From 06fedecc9178d44dd653429c69270fd0b44cde47 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 13:52:44 -0500 Subject: [PATCH 17/37] docs(repo): reorganize custom rulesets, update intro --- docs/guides/4-custom-rulesets.md | 201 ++++++++++++++++--------------- 1 file changed, 101 insertions(+), 100 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 95b32b7db..88e18129c 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -1,19 +1,20 @@ # Custom Rulesets -Customizing existing rulesets might be all you need at first, but at some point, you will want to make a custom ruleset. For example, the OpenAPI and AsyncAPI rulesets help create better quality descriptions of APIs, but you could create a custom ruleset to tell you how to make better APIs. This approach is how huge companies automate [API Style Guides](https://stoplight.io/api-style-guides-guidelines-and-best-practices/?utm_source=github&utm_medium=spectral&utm_campaign=docs), instead of writing up giant Wiki documents that nobody reads. +Customizing existing rulesets might be all you need at first, but at some point, you will want to make a custom ruleset. For example, the OpenAPI and AsyncAPI rulesets help create API descriptions that are valid according to their specifications, but you could create a custom ruleset to tell you how to make better APIs. This approach is how huge companies automate [API Style Guides](https://stoplight.io/api-style-guides-guidelines-and-best-practices/?utm_source=github&utm_medium=spectral&utm_campaign=docs), instead of writing up giant Wiki documents. -If you'd like to make sure your APIs are consistent and high quality even before they're built, create a ruleset with rules that define how URLs should work, what security schemes are appropriate, or what error formats should be used. Read our article _[Six Things You Should Include in Your API Style Guide](https://blog.stoplight.io/six-things-you-should-include-in-your-api-style-guide?utm_source=github&utm_medium=spectral&utm_campaign=docs)._ - -Or you can create a custom ruleset to make sure your Jekyll or Gatsby custom data is valid. Whatever you want to do, to start with you'll need to create some rules. +Let's look through the various keywords that make up a ruleset, so you can learn how to tweak a distributed ruleset to work for you, or make your own ruleset from scratch to power your organizations API Style Guide. ## Ruleset Properties -There are four properties that can be used at the root level of a ruleset: +There are five properties that can be used at the root level of a ruleset: - `rules` (required): An array of rules. -- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. - `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. +- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. - `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. +- `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. + +Rules are at the core of how rulesets work, so let's look at how to create a rule and its properties. ## Add Rules @@ -52,45 +53,6 @@ The `severity` keyword is optional and can be `error`, `warn`, `info`, or `hint` The default value is `warn`. -### Resolved - -By default, Spectral processes each rule on a "resolved" document (a file where -all `$ref` JSON Schema references have been replaced with the objects they point -to). While this is typically the desired behavior, there are some use cases -where you may need to run a rule on the "raw" un-resolved document. - -For example, if you want to enforce conventions on the folder structure used for -[splitting up -documents](https://blog.stoplight.io/keeping-openapi-dry-and-portable?utm_medium=spectral&utm_source=github&utm_campaign=docs). - -If your rule needs to access the raw `$ref` reference values, you can set `resolved: false` to allow the rule to receive the raw un-resolved version of the document. Otherwise `resolved: true` is the default. - -Here's an example of a rule that can access `$ref` values: - -```yaml -rules: - my-rule-name: - description: Parameters must be references - given: $.paths[*][get,post,put,delete,options] - severity: error - resolved: false - then: - field: parameters - function: schema - functionOptions: - schema: - type: array - items: - type: object - properties: - $ref: - type: string - required: - - $ref -``` - -**In most cases, you will want to operate on a resolved document.** - ### Then The `then` part of the rule explains which function to apply to the `given` JSONPath. The function you apply [may be one of the core functions](../reference/functions.md) or it may be [a custom function](./5-custom-functions.md). @@ -140,6 +102,45 @@ contact-properties: function: truthy ``` +### Resolved + +By default, Spectral processes each rule on a "resolved" document (a file where +all `$ref` JSON Schema references have been replaced with the objects they point +to). While this is typically the desired behavior, there are some use cases +where you may need to run a rule on the "raw" un-resolved document. + +For example, if you want to enforce conventions on the folder structure used for +[splitting up +documents](https://blog.stoplight.io/keeping-openapi-dry-and-portable?utm_medium=spectral&utm_source=github&utm_campaign=docs). + +If your rule needs to access the raw `$ref` reference values, you can set `resolved: false` to allow the rule to receive the raw un-resolved version of the document. Otherwise `resolved: true` is the default. + +Here's an example of a rule that can access `$ref` values: + +```yaml +rules: + my-rule-name: + description: Parameters must be references + given: $.paths[*][get,post,put,delete,options] + severity: error + resolved: false + then: + field: parameters + function: schema + functionOptions: + schema: + type: array + items: + type: object + properties: + $ref: + type: string + required: + - $ref +``` + +**In most cases, you will want to operate on a resolved document.** + ### Message To help you create meaningful messages for results, Spectral comes with a couple of placeholders that are evaluated at runtime. @@ -166,61 +167,6 @@ message: "{{value}} is greater than 0" message: "{{path}} cannot point at remote reference" ``` -## Parsing Options - - - -If you do not care about duplicate keys or invalid values (such as non-string mapping keys in YAML), you can tune their severity using the `parserOptions` setting. - -```yaml -extends: spectral:oas -parserOptions: - duplicateKeys: warn # error is the default value - incompatibleValues: off # error is the default value -``` - -`parserOptions` is not inherited by extended rulesets. - -## Documentation URL - -Optionally provide a documentation URL to your ruleset in order to help end-users find more information about various warnings. Result messages will sometimes be more than enough to explain what the problem is, but it can also be beneficial to explain _why_ a message exists, and this is a great place to do that. - -The rule name is appended to the link as an anchor. - -```yaml -# 👇 This line allows people to find more information -documentationUrl: https://www.example.com/docs/api-style-guide.md -rules: - no-http-basic: - description: "Consider a more secure alternative to HTTP Basic." - message: "HTTP Basic is a pretty insecure way to pass credentials around, please consider an alternative." - severity: error - given: $.components.securitySchemes[*] - then: - field: scheme - function: pattern - functionOptions: - notMatch: basic -``` - -In this example, violations of the `no-http-basic` rule would indicate `https://www.example.com/docs/api-style-guide.md#no-http-basic` as the location for finding out more about the rule. - -If no `documentationUrl` is provided, no links will show up, and users will just have to rely on the error messages to figure out how the errors can be fixed. - -If you wish to override a documentation URL for a particular rule, you can do so by specifying `documentationUrl`. - -```yaml -extends: spectral:oas -rules: - tag-description: - description: Please provide a description for each tag. - documentationUrl: https://www.example.com/docs/tag-description.md - given: $.tags[*] - then: - field: description - function: truthy -``` - ## Formats Formats are an optional way to specify which API description formats a rule, or ruleset, is applicable to. Currently Spectral supports these formats: @@ -299,6 +245,61 @@ rules: Custom formats can be registered via the [JS API](../guides/3-javascript.md), but the [CLI](../guides/2-cli.md) is limited to using the predefined formats. +## Documentation URL + +Optionally provide a documentation URL to your ruleset in order to help end-users find more information about various warnings. Result messages will sometimes be more than enough to explain what the problem is, but it can also be beneficial to explain _why_ a message exists, and this is a great place to do that. + +The rule name is appended to the link as an anchor. + +```yaml +# 👇 This line allows people to find more information +documentationUrl: https://www.example.com/docs/api-style-guide.md +rules: + no-http-basic: + description: "Consider a more secure alternative to HTTP Basic." + message: "HTTP Basic is a pretty insecure way to pass credentials around, please consider an alternative." + severity: error + given: $.components.securitySchemes[*] + then: + field: scheme + function: pattern + functionOptions: + notMatch: basic +``` + +In this example, violations of the `no-http-basic` rule would indicate `https://www.example.com/docs/api-style-guide.md#no-http-basic` as the location for finding out more about the rule. + +If no `documentationUrl` is provided, no links will show up, and users will just have to rely on the error messages to figure out how the errors can be fixed. + +If you wish to override a documentation URL for a particular rule, you can do so by specifying `documentationUrl`. + +```yaml +extends: spectral:oas +rules: + tag-description: + description: Please provide a description for each tag. + documentationUrl: https://www.example.com/docs/tag-description.md + given: $.tags[*] + then: + field: description + function: truthy +``` + +## Parsing Options + + + +If you do not care about duplicate keys or invalid values (such as non-string mapping keys in YAML), you can tune their severity using the `parserOptions` setting. + +```yaml +extends: spectral:oas +parserOptions: + duplicateKeys: warn # error is the default value + incompatibleValues: off # error is the default value +``` + +`parserOptions` is not inherited by extended rulesets. + ## Core Rulesets Spectral comes with two rulesets included: From d6dd30d20c0a0dea0185c5f5c2072c5df69120a2 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:08:08 -0500 Subject: [PATCH 18/37] docs(repo): small clarification for formats --- docs/guides/4-custom-rulesets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 88e18129c..10bd72543 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -10,7 +10,7 @@ There are five properties that can be used at the root level of a ruleset: - `rules` (required): An array of rules. - `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. -- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. +- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. - `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. - `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. From 8d16c4eedbea6da20fbd2138a258ec2d3caee229 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:09:45 -0500 Subject: [PATCH 19/37] docs(repo): remove link --- docs/guides/4-custom-rulesets.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 10bd72543..e27399cf9 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -306,5 +306,3 @@ Spectral comes with two rulesets included: - `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) - `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) - -You can also make your own: read more about [Custom Rulesets](../guides/4-custom-rulesets.md). From f55d3280c730ea2565ab9a71e4bbb7551d4408b5 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:10:49 -0500 Subject: [PATCH 20/37] docs(repo): remove unnecessary words --- docs/getting-started/3-rulesets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 15c165082..e18111dd9 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -57,4 +57,4 @@ Breaking down each part of the rule: For more information about creating Rulesets and Rules, see [Custom Rulesets](../guides/4-custom-rulesets.md). -For more examples of existing rulesets you can use, see [Real-World Rulesets](../../README.md#🌎-real-world-rulesets) in our README. +For more examples of existing rulesets you can use, see [Real-World Rulesets](../../README.md#🌎-real-world-rulesets). From e6628f6b25403eacf6b3d916d85d0e39c4ecb5ae Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:12:41 -0500 Subject: [PATCH 21/37] docs(repo): fix broken link --- docs/getting-started/3-rulesets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index e18111dd9..ae2381e3d 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -57,4 +57,4 @@ Breaking down each part of the rule: For more information about creating Rulesets and Rules, see [Custom Rulesets](../guides/4-custom-rulesets.md). -For more examples of existing rulesets you can use, see [Real-World Rulesets](../../README.md#🌎-real-world-rulesets). +For more examples of existing rulesets you can use, see [Real-World Rulesets](../../README.md#-real-world-rulesets). From 797dc90dc8121fc035d4d5e113fbab170c1f0285 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:13:32 -0500 Subject: [PATCH 22/37] docs(repo): remove core rulesets section --- docs/guides/4-custom-rulesets.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index e27399cf9..80fa97288 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -299,10 +299,3 @@ parserOptions: ``` `parserOptions` is not inherited by extended rulesets. - -## Core Rulesets - -Spectral comes with two rulesets included: - -- `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) -- `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) From 00a7b355d3a734952dcb34ab4ed4f98a0235329b Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:17:29 -0500 Subject: [PATCH 23/37] docs(repo): update rules section --- docs/guides/4-custom-rulesets.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 80fa97288..12d5addf2 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -16,9 +16,9 @@ There are five properties that can be used at the root level of a ruleset: Rules are at the core of how rulesets work, so let's look at how to create a rule and its properties. -## Add Rules +## Rules -Add your own rules under the `rules` property in your ruleset file. +Rules can be added under the `rules` property in your ruleset file. ```yaml rules: @@ -31,7 +31,7 @@ rules: function: truthy ``` -Spectral has [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. +The example above is a valid ruleset with a single rule. ## Rules Properties From d9bc8df8b0fdcf454d44c0032ed8da944e4b072c Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:19:34 -0500 Subject: [PATCH 24/37] docs(repo): delete rules header and move content --- docs/guides/4-custom-rulesets.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 12d5addf2..0afd97ff2 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -16,7 +16,7 @@ There are five properties that can be used at the root level of a ruleset: Rules are at the core of how rulesets work, so let's look at how to create a rule and its properties. -## Rules +## Rules Properties Rules can be added under the `rules` property in your ruleset file. @@ -31,9 +31,7 @@ rules: function: truthy ``` -The example above is a valid ruleset with a single rule. - -## Rules Properties +The example above is a valid ruleset with a single rule. Let's look at all the properties that can be used for a rule. ### Given From 6b9c57662064cd6de2c39a7d6ef771e097a785a0 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Tue, 18 Oct 2022 14:25:06 -0500 Subject: [PATCH 25/37] docs(repo): add properties to ruleset and rules list --- docs/guides/4-custom-rulesets.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 0afd97ff2..e6f1c6f16 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -13,6 +13,8 @@ There are five properties that can be used at the root level of a ruleset: - `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. - `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. - `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. +- `aliases` (optional): +- `overrides` (optional): Rules are at the core of how rulesets work, so let's look at how to create a rule and its properties. @@ -31,7 +33,19 @@ rules: function: truthy ``` -The example above is a valid ruleset with a single rule. Let's look at all the properties that can be used for a rule. +The example above is a valid ruleset with a single rule that can be used to lint an OpenAPI description, and validate that all `tags` have a description field. + +Rules can have the following properties: + +- `description` +- `message` +- `formats` +- `recommended` +- `severity` +- `given` +- `then` + +Let's look at all the properties that can be used for a rule. ### Given From 068c1ac9a7ca4af5a7239d4fe5d62b6cfafeb68f Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 11:52:34 -0500 Subject: [PATCH 26/37] docs(repo): change Rulesets title to Create a Ruleset --- toc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toc.json b/toc.json index d3a015f0c..0dcac31c6 100644 --- a/toc.json +++ b/toc.json @@ -21,7 +21,7 @@ }, { "type": "item", - "title": "Rulesets", + "title": "Create a Ruleset", "uri": "/docs/getting-started/3-rulesets.md" }, { From df54b5fb6fb45c1358fdd1a03358e75e664d294a Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 13:36:09 -0500 Subject: [PATCH 27/37] docs(repo): update headings --- docs/getting-started/3-rulesets.md | 4 ++-- docs/guides/4-custom-rulesets.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index ae2381e3d..7c49122a5 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -1,4 +1,4 @@ -# Rulesets +# Create a Ruleset Rulesets are collections of rules written in JSON, YAML, or [JavaScript](../guides/4-custom-rulesets.md#alternative-js-ruleset-format), which can be used to power powerful linting of other JSON or YAML files, such as OpenAPI or AsyncAPI descriptions. Meta, we know! 😎 @@ -6,7 +6,7 @@ Ruleset files are often named `.spectral.yaml`, but that's not a requirement. Rules take certain parameters and then call functions on parts of another YAML or JSON object being linted. -## Create a Ruleset +## Extend an Existing Ruleset The fastest way to create a ruleset is to use the `extends` property to leverage an existing ruleset. diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index e6f1c6f16..1816ab07d 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -1,4 +1,4 @@ -# Custom Rulesets +# Rulesets Customizing existing rulesets might be all you need at first, but at some point, you will want to make a custom ruleset. For example, the OpenAPI and AsyncAPI rulesets help create API descriptions that are valid according to their specifications, but you could create a custom ruleset to tell you how to make better APIs. This approach is how huge companies automate [API Style Guides](https://stoplight.io/api-style-guides-guidelines-and-best-practices/?utm_source=github&utm_medium=spectral&utm_campaign=docs), instead of writing up giant Wiki documents. From b7cba6bb109a66dde99ff8ec5c04ec03d17328b8 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 13:37:40 -0500 Subject: [PATCH 28/37] docs(repo): update toc Custom Rulesets to Rulesets --- toc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toc.json b/toc.json index 0dcac31c6..8d520fd72 100644 --- a/toc.json +++ b/toc.json @@ -55,7 +55,7 @@ }, { "type": "group", - "title": "Custom Rulesets", + "title": "Rulesets", "items": [ { "type": "item", From bcec07da3536f5bd664130ccc1a4608925e18c5f Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 16:20:49 -0500 Subject: [PATCH 29/37] docs(repo): break up rules into its own page --- docs/guides/4-custom-rulesets.md | 173 ++----------------------------- docs/guides/4f-rules.md | 164 +++++++++++++++++++++++++++++ toc.json | 5 + 3 files changed, 175 insertions(+), 167 deletions(-) create mode 100644 docs/guides/4f-rules.md diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 1816ab07d..9bdc4c00d 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -1,8 +1,8 @@ # Rulesets -Customizing existing rulesets might be all you need at first, but at some point, you will want to make a custom ruleset. For example, the OpenAPI and AsyncAPI rulesets help create API descriptions that are valid according to their specifications, but you could create a custom ruleset to tell you how to make better APIs. This approach is how huge companies automate [API Style Guides](https://stoplight.io/api-style-guides-guidelines-and-best-practices/?utm_source=github&utm_medium=spectral&utm_campaign=docs), instead of writing up giant Wiki documents. +Spectral comes with two rulesets built-in: [OpenAPI](../reference/openapi-rules.md) and [AsyncAPI](../reference/asyncapi-rules.md). They're a good point for getting started, but the true power of Spectral comes with customizing and creating a ruleset that fits your project or organization. Creating a ruleset can help you and your team level up your API design and API development process, and help you create better APIs. -Let's look through the various keywords that make up a ruleset, so you can learn how to tweak a distributed ruleset to work for you, or make your own ruleset from scratch to power your organizations API Style Guide. +Let's look through the various keywords that make up a ruleset, so you can learn how to tweak a distributed ruleset to work for you, or make your own ruleset from scratch to power your organizations [API Style Guide](https://stoplight.io/api-style-guides-guidelines-and-best-practices/?utm_source=github&utm_medium=spectral&utm_campaign=docs). ## Ruleset Properties @@ -16,170 +16,9 @@ There are five properties that can be used at the root level of a ruleset: - `aliases` (optional): - `overrides` (optional): -Rules are at the core of how rulesets work, so let's look at how to create a rule and its properties. +Rules are the most important part of a ruleset. For more details on rules and its properties, see [Rules](./4f-rules.md). -## Rules Properties - -Rules can be added under the `rules` property in your ruleset file. - -```yaml -rules: - my-rule-name: - description: Tags must have a description. - given: $.tags[*] - severity: error - then: - field: description - function: truthy -``` - -The example above is a valid ruleset with a single rule that can be used to lint an OpenAPI description, and validate that all `tags` have a description field. - -Rules can have the following properties: - -- `description` -- `message` -- `formats` -- `recommended` -- `severity` -- `given` -- `then` - -Let's look at all the properties that can be used for a rule. - -### Given - -The `given` property is conceptually quite like a selector in CSS, in that it picks the part of the document to apply rules to. - -It has a specific syntax known as [JSONPath](https://goessner.net/articles/JsonPath/index.html), which if you are familiar with XPath is quite similar. JSONPath is not yet a standard (it [will be](https://tools.ietf.org/html/draft-normington-jsonpath-00) someday), and has a few competing implementations. Spectral uses [nimma](https://www.npmjs.com/package/nimma) as its main implementation, and sometimes resorts to [jsonpath-plus](https://www.npmjs.com/package/jsonpath-plus) to ensure a good backwards-compatibility. -Both of them support all the main JSONPath functionality and a little bit more, but this syntax may differ slightly from other JSONPath implementations. - -Your `given` value can be a string containing any valid JSONPath expression, or an array of expressions to apply a rule to multiple parts of a document. -You can also consume your [aliases](4c-aliases.md) here if you have some defined. - -Use the [JSONPath Online Evaluator](http://jsonpath.com/) to determine what `given` path you want. - -### Severity - -The `severity` keyword is optional and can be `error`, `warn`, `info`, or `hint`. - -The default value is `warn`. - -### Then - -The `then` part of the rule explains which function to apply to the `given` JSONPath. The function you apply [may be one of the core functions](../reference/functions.md) or it may be [a custom function](./5-custom-functions.md). - -`then` has two main keywords: - -```yaml -then: - field: description - function: truthy -``` - -The `field` keyword is optional and is used to apply the function to a specific property in an object. If omitted the function will be applied to the entire target of the `given` JSONPath. The value can also be `@key` to apply the rule to the keys of an object. - -```yaml -given: "$.responses" -then: - field: "@key" - function: pattern - functionOptions: - match: "^[0-9]+$" -``` - -The above [`pattern` based rule](../reference/functions.md#pattern) would error on `456avbas` as it is not numeric. - -```yaml -responses: - 123: - foo: bar - 456avbas: - foo: bar -``` - -You can also have multiple `then`s to target different properties in the same object, or to use different functions. For example, you can have one rule that will check if an object has multiple properties: - -```yaml -contact-properties: - description: Contact object must have "name", "url", and "email". - given: $.info.contact - severity: warn - then: - - field: name - function: truthy - - field: url - function: truthy - - field: email - function: truthy -``` - -### Resolved - -By default, Spectral processes each rule on a "resolved" document (a file where -all `$ref` JSON Schema references have been replaced with the objects they point -to). While this is typically the desired behavior, there are some use cases -where you may need to run a rule on the "raw" un-resolved document. - -For example, if you want to enforce conventions on the folder structure used for -[splitting up -documents](https://blog.stoplight.io/keeping-openapi-dry-and-portable?utm_medium=spectral&utm_source=github&utm_campaign=docs). - -If your rule needs to access the raw `$ref` reference values, you can set `resolved: false` to allow the rule to receive the raw un-resolved version of the document. Otherwise `resolved: true` is the default. - -Here's an example of a rule that can access `$ref` values: - -```yaml -rules: - my-rule-name: - description: Parameters must be references - given: $.paths[*][get,post,put,delete,options] - severity: error - resolved: false - then: - field: parameters - function: schema - functionOptions: - schema: - type: array - items: - type: object - properties: - $ref: - type: string - required: - - $ref -``` - -**In most cases, you will want to operate on a resolved document.** - -### Message - -To help you create meaningful messages for results, Spectral comes with a couple of placeholders that are evaluated at runtime. - -- `{{error}}` - the error returned by function -- `{{description}}` - the description set on the rule -- `{{path}}` - the whole error path -- `{{property}}` - the last segment of error path -- `{{value}}` - the linted value - -```yaml -message: "{{error}}" # will output the message generated by then.function -``` - -```yaml -message: "The value of '{{property}}' property must equal 'foo'" -``` - -```yaml -message: "{{value}} is greater than 0" -``` - -```yaml -message: "{{path}} cannot point at remote reference" -``` - -## Formats +### Formats Formats are an optional way to specify which API description formats a rule, or ruleset, is applicable to. Currently Spectral supports these formats: @@ -257,7 +96,7 @@ rules: Custom formats can be registered via the [JS API](../guides/3-javascript.md), but the [CLI](../guides/2-cli.md) is limited to using the predefined formats. -## Documentation URL +### Documentation URL Optionally provide a documentation URL to your ruleset in order to help end-users find more information about various warnings. Result messages will sometimes be more than enough to explain what the problem is, but it can also be beneficial to explain _why_ a message exists, and this is a great place to do that. @@ -297,7 +136,7 @@ rules: function: truthy ``` -## Parsing Options +### Parsing Options diff --git a/docs/guides/4f-rules.md b/docs/guides/4f-rules.md new file mode 100644 index 000000000..c6ce2add3 --- /dev/null +++ b/docs/guides/4f-rules.md @@ -0,0 +1,164 @@ +# Rules + +Rules are at the core of how rulesets work, so let's look at how to create a rule and its properties. + +## Rules Properties + +Rules can be added under the `rules` property in your ruleset file. + +```yaml +rules: + my-rule-name: + description: Tags must have a description. + given: $.tags[*] + severity: error + then: + field: description + function: truthy +``` + +The example above is a valid ruleset with a single rule that can be used to lint an OpenAPI description, and validate that all `tags` have a description field. + +Rules can have the following properties: + +- `description` +- `message` +- `formats` +- `recommended` +- `severity` +- `given` +- `then` + +Let's look at all the properties that can be used for a rule. + +### Given + +The `given` property is conceptually quite like a selector in CSS, in that it picks the part of the document to apply rules to. + +It has a specific syntax known as [JSONPath](https://goessner.net/articles/JsonPath/index.html), which if you are familiar with XPath is quite similar. JSONPath is not yet a standard (it [will be](https://tools.ietf.org/html/draft-normington-jsonpath-00) someday), and has a few competing implementations. Spectral uses [nimma](https://www.npmjs.com/package/nimma) as its main implementation, and sometimes resorts to [jsonpath-plus](https://www.npmjs.com/package/jsonpath-plus) to ensure a good backwards-compatibility. +Both of them support all the main JSONPath functionality and a little bit more, but this syntax may differ slightly from other JSONPath implementations. + +Your `given` value can be a string containing any valid JSONPath expression, or an array of expressions to apply a rule to multiple parts of a document. +You can also consume your [aliases](4c-aliases.md) here if you have some defined. + +Use the [JSONPath Online Evaluator](http://jsonpath.com/) to determine what `given` path you want. + +### Severity + +The `severity` keyword is optional and can be `error`, `warn`, `info`, or `hint`. + +The default value is `warn`. + +### Then + +The `then` part of the rule explains which function to apply to the `given` JSONPath. The function you apply [may be one of the core functions](../reference/functions.md) or it may be [a custom function](./5-custom-functions.md). + +`then` has two main keywords: + +```yaml +then: + field: description + function: truthy +``` + +The `field` keyword is optional and is used to apply the function to a specific property in an object. If omitted the function will be applied to the entire target of the `given` JSONPath. The value can also be `@key` to apply the rule to the keys of an object. + +```yaml +given: "$.responses" +then: + field: "@key" + function: pattern + functionOptions: + match: "^[0-9]+$" +``` + +The above [`pattern` based rule](../reference/functions.md#pattern) would error on `456avbas` as it is not numeric. + +```yaml +responses: + 123: + foo: bar + 456avbas: + foo: bar +``` + +You can also have multiple `then`s to target different properties in the same object, or to use different functions. For example, you can have one rule that will check if an object has multiple properties: + +```yaml +contact-properties: + description: Contact object must have "name", "url", and "email". + given: $.info.contact + severity: warn + then: + - field: name + function: truthy + - field: url + function: truthy + - field: email + function: truthy +``` + +### Resolved + +By default, Spectral processes each rule on a "resolved" document (a file where +all `$ref` JSON Schema references have been replaced with the objects they point +to). While this is typically the desired behavior, there are some use cases +where you may need to run a rule on the "raw" un-resolved document. + +For example, if you want to enforce conventions on the folder structure used for +[splitting up +documents](https://blog.stoplight.io/keeping-openapi-dry-and-portable?utm_medium=spectral&utm_source=github&utm_campaign=docs). + +If your rule needs to access the raw `$ref` reference values, you can set `resolved: false` to allow the rule to receive the raw un-resolved version of the document. Otherwise `resolved: true` is the default. + +Here's an example of a rule that can access `$ref` values: + +```yaml +rules: + my-rule-name: + description: Parameters must be references + given: $.paths[*][get,post,put,delete,options] + severity: error + resolved: false + then: + field: parameters + function: schema + functionOptions: + schema: + type: array + items: + type: object + properties: + $ref: + type: string + required: + - $ref +``` + +**In most cases, you will want to operate on a resolved document.** + +### Message + +To help you create meaningful messages for results, Spectral comes with a couple of placeholders that are evaluated at runtime. + +- `{{error}}` - the error returned by function +- `{{description}}` - the description set on the rule +- `{{path}}` - the whole error path +- `{{property}}` - the last segment of error path +- `{{value}}` - the linted value + +```yaml +message: "{{error}}" # will output the message generated by then.function +``` + +```yaml +message: "The value of '{{property}}' property must equal 'foo'" +``` + +```yaml +message: "{{value}} is greater than 0" +``` + +```yaml +message: "{{path}} cannot point at remote reference" +``` diff --git a/toc.json b/toc.json index 8d520fd72..2f1dc4e6d 100644 --- a/toc.json +++ b/toc.json @@ -62,6 +62,11 @@ "title": "Overview", "uri": "/docs/guides/4-custom-rulesets.md" }, + { + "type": "item", + "title": "Rules", + "uri": "/docs/guides/4f-rules.md" + }, { "type": "item", "title": "Extends", From dfa55442677adea3c61b79bca3f994d1afbadd40 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 16:31:06 -0500 Subject: [PATCH 30/37] docs(repo): cleanup md --- docs/guides/4c-aliases.md | 2 ++ docs/guides/4d-overrides.md | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/guides/4c-aliases.md b/docs/guides/4c-aliases.md index 4ae05f52e..2f1ddb8c4 100644 --- a/docs/guides/4c-aliases.md +++ b/docs/guides/4c-aliases.md @@ -4,6 +4,7 @@ Targeting certain parts of an OpenAPI spec is powerful but it can become cumbers Define aliases for commonly used JSONPath expressions on a global level which can then be reused across the ruleset. Aliases can be defined in an array of key-value pairs at the root level of the ruleset, or alternatively, within an override. + It's similar to `given`, with the notable difference being the possibility to distinguish between different formats. **Example** @@ -41,6 +42,7 @@ aliases: ``` Now, if you referenced the `SharedParameterObject` alias, the chosen path would be determined based on the document you use. + For instance, if a given document matched OpenAPI 2.x, `$.parameters[*]` would be used as the JSONPath expression. Having a closer look at the example above, one may notice that it'd be still somewhat complicated to target _all_ Parameter Objects that a specific OpenAPI document may contain. To make it more feasible and avoid overly complex JSONPath expressions, `given` can be an array. diff --git a/docs/guides/4d-overrides.md b/docs/guides/4d-overrides.md index 01b61020a..c51cdbdc0 100644 --- a/docs/guides/4d-overrides.md +++ b/docs/guides/4d-overrides.md @@ -28,8 +28,7 @@ overrides: type: number ``` -To apply an override to particular elements of files, combine a glob for a filepath -with a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) after the anchor, i.e.: +To apply an override to particular elements of files, combine a glob for a filepath with a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) after the anchor, i.e.: ```yaml overrides: @@ -40,7 +39,9 @@ overrides: ``` JSON Pointers have a different syntax than JSON Paths used in the `given` component of a rule. + In JSON Pointers, path components are prefixed with a "/" and then concatenated to form the pointer. + Since "/" has a special meaning in JSON pointer, it must be encoded as "~1" when it appears in a component, and "~" must be encoded as "~0". You can test JSON Pointer expressions in the [JSON Query online evaluator](https://www.jsonquerytool.com/) by choosing "JSONPointer" as the Transform. From a4ea27626995d8b250e71bb47101e2b978084bdc Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 16:31:31 -0500 Subject: [PATCH 31/37] docs(repo): update ruleset properties section --- docs/guides/4-custom-rulesets.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 9bdc4c00d..b341eb25b 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -8,13 +8,13 @@ Let's look through the various keywords that make up a ruleset, so you can learn There are five properties that can be used at the root level of a ruleset: -- `rules` (required): An array of rules. -- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. -- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. -- `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. -- `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. -- `aliases` (optional): -- `overrides` (optional): +- `rules` (required): An array of rules. See [Rules](./4f-rules.md) for more details. +- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. See [Extends](./4a-extends.md) for more details. +- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](#formats) for more details. +- `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. See [Documentation URL](#documentation-url) for more details. +- `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. See [Parsing Options](#parsing-options) for more details. +- `aliases` (optional): An array of key-value pairs that can be used to define commonly used JSONPath expressions, to be reused across a ruleset. See [Aliases](./4c-aliases.md) for more details. +- `overrides` (optional): Can be used to customize which formats, files, or parts of files, that a ruleset should be applied to. See [Overrides](./4d-overrides.md) for more details. Rules are the most important part of a ruleset. For more details on rules and its properties, see [Rules](./4f-rules.md). From 5546a21cf8ffe7499bc94a37cd431b316796fbec Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 16:54:11 -0500 Subject: [PATCH 32/37] docs(repo): update rules properties --- docs/guides/4f-rules.md | 79 +++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/docs/guides/4f-rules.md b/docs/guides/4f-rules.md index c6ce2add3..c04e26a7f 100644 --- a/docs/guides/4f-rules.md +++ b/docs/guides/4f-rules.md @@ -21,13 +21,14 @@ The example above is a valid ruleset with a single rule that can be used to lint Rules can have the following properties: -- `description` -- `message` -- `formats` -- `recommended` -- `severity` -- `given` -- `then` +- `given` (required): The part of the document the rule should be applied to. Uses the [JSONPath](https://goessner.net/articles/JsonPath/index.html) syntax. +- `then` (required): Describes which function should be applied to the `given` part of the document. Can be used with a [core function](../reference/functions.md) or [custom function](./5-custom-functions.md). +- `description` (optional): A short description of the rule. +- `message` (optional): A message that will be displayed in the `spectral lint` output. Can be customized to use placeholder values that are evaluated at runtime, such as `{{description}}` or `{{error}}`. +- `severity` (optional): The severity of the rule. Used to differentiate between rules that must be followed (`error`) and warnings or hints. Default value is `warn`. +- `formats` (optional): The format that the rule should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](./4-custom-rulesets.md#formats) for more details. +- `recommended` (optional): Recommended is a property that is used when extending a ruleset, where users can define if they would like to enforce all rules (`recommended` set to `true` and `false`) or only recommended rules (`recommended` set to `true`). Recommended can be used to help slowly roll out a ruleset across API landscapes with a lot of legacy APIs. Default value is `true`. See [Recommended](./4b-recommended.md) for more details. +- `resolved` (optional): Used to apply a rule to a document that is not "resolved", where `$ref` JSON Schema references have not been replaced with the objects they point to. Let's look at all the properties that can be used for a rule. @@ -43,12 +44,6 @@ You can also consume your [aliases](4c-aliases.md) here if you have some defined Use the [JSONPath Online Evaluator](http://jsonpath.com/) to determine what `given` path you want. -### Severity - -The `severity` keyword is optional and can be `error`, `warn`, `info`, or `hint`. - -The default value is `warn`. - ### Then The `then` part of the rule explains which function to apply to the `given` JSONPath. The function you apply [may be one of the core functions](../reference/functions.md) or it may be [a custom function](./5-custom-functions.md). @@ -98,6 +93,38 @@ contact-properties: function: truthy ``` +### Message + +To help you create meaningful messages for results, Spectral comes with a couple of placeholders that are evaluated at runtime. + +- `{{error}}` - the error returned by function +- `{{description}}` - the description set on the rule +- `{{path}}` - the whole error path +- `{{property}}` - the last segment of error path +- `{{value}}` - the linted value + +```yaml +message: "{{error}}" # will output the message generated by then.function +``` + +```yaml +message: "The value of '{{property}}' property must equal 'foo'" +``` + +```yaml +message: "{{value}} is greater than 0" +``` + +```yaml +message: "{{path}} cannot point at remote reference" +``` + +### Severity + +The `severity` keyword is optional and can be `error`, `warn`, `info`, or `hint`. + +The default value is `warn`. + ### Resolved By default, Spectral processes each rule on a "resolved" document (a file where @@ -136,29 +163,3 @@ rules: ``` **In most cases, you will want to operate on a resolved document.** - -### Message - -To help you create meaningful messages for results, Spectral comes with a couple of placeholders that are evaluated at runtime. - -- `{{error}}` - the error returned by function -- `{{description}}` - the description set on the rule -- `{{path}}` - the whole error path -- `{{property}}` - the last segment of error path -- `{{value}}` - the linted value - -```yaml -message: "{{error}}" # will output the message generated by then.function -``` - -```yaml -message: "The value of '{{property}}' property must equal 'foo'" -``` - -```yaml -message: "{{value}} is greater than 0" -``` - -```yaml -message: "{{path}} cannot point at remote reference" -``` From d5b8de3045e8a517eaef7b8a4a688273dc3fc872 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Wed, 19 Oct 2022 16:56:49 -0500 Subject: [PATCH 33/37] docs(repo): rewording --- docs/guides/4-custom-rulesets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index b341eb25b..a712523bd 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -1,6 +1,6 @@ # Rulesets -Spectral comes with two rulesets built-in: [OpenAPI](../reference/openapi-rules.md) and [AsyncAPI](../reference/asyncapi-rules.md). They're a good point for getting started, but the true power of Spectral comes with customizing and creating a ruleset that fits your project or organization. Creating a ruleset can help you and your team level up your API design and API development process, and help you create better APIs. +Spectral comes with two rulesets built-in: [OpenAPI](../reference/openapi-rules.md) and [AsyncAPI](../reference/asyncapi-rules.md). They're good starting points, but the true power of Spectral comes with customizing and creating a ruleset that fits your project or organization. Creating a ruleset can help you and your team level up your API design and API development process, and help you create better APIs. Let's look through the various keywords that make up a ruleset, so you can learn how to tweak a distributed ruleset to work for you, or make your own ruleset from scratch to power your organizations [API Style Guide](https://stoplight.io/api-style-guides-guidelines-and-best-practices/?utm_source=github&utm_medium=spectral&utm_campaign=docs). From 31eb749ad2a4f11816d880588f0f16a9fa9a397a Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Thu, 20 Oct 2022 14:10:28 -0500 Subject: [PATCH 34/37] docs(repo): rename files --- docs/guides/4-custom-rulesets.md | 6 +++--- docs/guides/{4f-rules.md => 4a-rules.md} | 2 +- docs/guides/{4a-extends.md => 4b-extends.md} | 0 docs/guides/{4b-recommended.md => 4e-recommended.md} | 0 docs/guides/{4e-js-rulesets.md => 4f-js-rulesets.md} | 0 toc.json | 8 ++++---- 6 files changed, 8 insertions(+), 8 deletions(-) rename docs/guides/{4f-rules.md => 4a-rules.md} (99%) rename docs/guides/{4a-extends.md => 4b-extends.md} (100%) rename docs/guides/{4b-recommended.md => 4e-recommended.md} (100%) rename docs/guides/{4e-js-rulesets.md => 4f-js-rulesets.md} (100%) diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index a712523bd..12044b08b 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -8,15 +8,15 @@ Let's look through the various keywords that make up a ruleset, so you can learn There are five properties that can be used at the root level of a ruleset: -- `rules` (required): An array of rules. See [Rules](./4f-rules.md) for more details. -- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. See [Extends](./4a-extends.md) for more details. +- `rules` (required): An array of rules. See [Rules](./4a-rules.md) for more details. +- `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. See [Extends](./4b-extends.md) for more details. - `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](#formats) for more details. - `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. See [Documentation URL](#documentation-url) for more details. - `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. See [Parsing Options](#parsing-options) for more details. - `aliases` (optional): An array of key-value pairs that can be used to define commonly used JSONPath expressions, to be reused across a ruleset. See [Aliases](./4c-aliases.md) for more details. - `overrides` (optional): Can be used to customize which formats, files, or parts of files, that a ruleset should be applied to. See [Overrides](./4d-overrides.md) for more details. -Rules are the most important part of a ruleset. For more details on rules and its properties, see [Rules](./4f-rules.md). +Rules are the most important part of a ruleset. For more details on rules and its properties, see [Rules](./4a-rules.md). ### Formats diff --git a/docs/guides/4f-rules.md b/docs/guides/4a-rules.md similarity index 99% rename from docs/guides/4f-rules.md rename to docs/guides/4a-rules.md index c04e26a7f..46e8f8791 100644 --- a/docs/guides/4f-rules.md +++ b/docs/guides/4a-rules.md @@ -27,7 +27,7 @@ Rules can have the following properties: - `message` (optional): A message that will be displayed in the `spectral lint` output. Can be customized to use placeholder values that are evaluated at runtime, such as `{{description}}` or `{{error}}`. - `severity` (optional): The severity of the rule. Used to differentiate between rules that must be followed (`error`) and warnings or hints. Default value is `warn`. - `formats` (optional): The format that the rule should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](./4-custom-rulesets.md#formats) for more details. -- `recommended` (optional): Recommended is a property that is used when extending a ruleset, where users can define if they would like to enforce all rules (`recommended` set to `true` and `false`) or only recommended rules (`recommended` set to `true`). Recommended can be used to help slowly roll out a ruleset across API landscapes with a lot of legacy APIs. Default value is `true`. See [Recommended](./4b-recommended.md) for more details. +- `recommended` (optional): Recommended is a property that is used when extending a ruleset, where users can define if they would like to enforce all rules (`recommended` set to `true` and `false`) or only recommended rules (`recommended` set to `true`). Recommended can be used to help slowly roll out a ruleset across API landscapes with a lot of legacy APIs. Default value is `true`. See [Recommended](./4e-recommended.md) for more details. - `resolved` (optional): Used to apply a rule to a document that is not "resolved", where `$ref` JSON Schema references have not been replaced with the objects they point to. Let's look at all the properties that can be used for a rule. diff --git a/docs/guides/4a-extends.md b/docs/guides/4b-extends.md similarity index 100% rename from docs/guides/4a-extends.md rename to docs/guides/4b-extends.md diff --git a/docs/guides/4b-recommended.md b/docs/guides/4e-recommended.md similarity index 100% rename from docs/guides/4b-recommended.md rename to docs/guides/4e-recommended.md diff --git a/docs/guides/4e-js-rulesets.md b/docs/guides/4f-js-rulesets.md similarity index 100% rename from docs/guides/4e-js-rulesets.md rename to docs/guides/4f-js-rulesets.md diff --git a/toc.json b/toc.json index 2f1dc4e6d..b5927e406 100644 --- a/toc.json +++ b/toc.json @@ -65,17 +65,17 @@ { "type": "item", "title": "Rules", - "uri": "/docs/guides/4f-rules.md" + "uri": "/docs/guides/4a-rules.md" }, { "type": "item", "title": "Extends", - "uri": "/docs/guides/4a-extends.md" + "uri": "/docs/guides/4b-extends.md" }, { "type": "item", "title": "Recommended", - "uri": "/docs/guides/4b-recommended.md" + "uri": "/docs/guides/4e-recommended.md" }, { "type": "item", @@ -90,7 +90,7 @@ { "type": "item", "title": "JavaScript Ruleset Format", - "uri": "/docs/guides/4e-js-rulesets.md" + "uri": "/docs/guides/4f-js-rulesets.md" } ] }, From f5c83ef83363f4f1405ef4743946fbd30236f93e Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Thu, 20 Oct 2022 14:12:26 -0500 Subject: [PATCH 35/37] docs(repo): update toc --- toc.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/toc.json b/toc.json index b5927e406..bb3bb6653 100644 --- a/toc.json +++ b/toc.json @@ -72,11 +72,6 @@ "title": "Extends", "uri": "/docs/guides/4b-extends.md" }, - { - "type": "item", - "title": "Recommended", - "uri": "/docs/guides/4e-recommended.md" - }, { "type": "item", "title": "Aliases", @@ -87,6 +82,11 @@ "title": "Overrides", "uri": "/docs/guides/4d-overrides.md" }, + { + "type": "item", + "title": "Recommended", + "uri": "/docs/guides/4e-recommended.md" + }, { "type": "item", "title": "JavaScript Ruleset Format", From bec237855dcc1b70bbf7d1dab4868d6c4fc001d6 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Thu, 20 Oct 2022 14:17:04 -0500 Subject: [PATCH 36/37] docs(repo): fix link --- docs/guides/4c-aliases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/4c-aliases.md b/docs/guides/4c-aliases.md index 2f1ddb8c4..3a906aca0 100644 --- a/docs/guides/4c-aliases.md +++ b/docs/guides/4c-aliases.md @@ -70,7 +70,7 @@ aliases: - $.components.parameters[*] ``` -Rulesets can then reference aliases in the [given](#given) keyword, either in full: `"given": "#Paths"`, or use it as a prefix for further JSONPath syntax, like dot notation: `"given": "#ParameterObject.name"`. +Rulesets can then reference aliases in the [given](./4a-rules.md#given) keyword, either in full: `"given": "#Paths"`, or use it as a prefix for further JSONPath syntax, like dot notation: `"given": "#ParameterObject.name"`. Keep in mind that an alias has to be explicitly defined either at the root level or inside an override. This is to avoid ambiguity. From 116337182257b1c42d7def7990aa442337e29e15 Mon Sep 17 00:00:00 2001 From: Heitor Tashiro Sergent Date: Fri, 21 Oct 2022 15:42:11 -0500 Subject: [PATCH 37/37] docs(repo): pam feedback --- docs/getting-started/3-rulesets.md | 8 ++++---- docs/guides/4-custom-rulesets.md | 27 ++++----------------------- docs/guides/4a-rules.md | 21 +++++++-------------- docs/guides/4b-extends.md | 6 +++--- docs/guides/4c-aliases.md | 3 ++- docs/guides/4d-overrides.md | 4 ++-- docs/guides/4e-recommended.md | 8 ++++---- docs/guides/4f-js-rulesets.md | 14 +++++++++----- 8 files changed, 35 insertions(+), 56 deletions(-) diff --git a/docs/getting-started/3-rulesets.md b/docs/getting-started/3-rulesets.md index 7c49122a5..f6aadf051 100644 --- a/docs/getting-started/3-rulesets.md +++ b/docs/getting-started/3-rulesets.md @@ -15,13 +15,13 @@ Spectral comes with two built-in rulesets: - `spectral:oas` - [OpenAPI v2/v3 rules](./4-openapi.md) - `spectral:asyncapi` - [AsyncAPI v2 rules](./5-asyncapi.md) -To create a ruleset that extends both rulesets, in your terminal run: +To create a ruleset that extends both rulesets, open your terminal and run: ```bash echo 'extends: ["spectral:oas", "spectral:asyncapi"]' > .spectral.yaml ``` -The newly created ruleset file can then be used to lint any OpenAPI v2/v3 or AsyncAPI descriptions by using the `spectral lint` command: +The newly created ruleset file can then be used to lint any OpenAPI v2/v3 or AsyncAPI descriptions using the `spectral lint` command: ```bash spectral lint myapifile.yaml @@ -48,8 +48,8 @@ The example above is a rule that can be used to validate an OpenAPI description. Breaking down each part of the rule: -- `description` and `message` will help users quickly understand what the goal of the rule is -- `severity` will help define the importance of following the rule +- `description` and `message` help users quickly understand what the goal of the rule is +- `severity` help define the importance of following the rule - The `given` keyword tells Spectral what part of the JSON or YAML file to target by using [JSONPath](http://jsonpath.com/) (Spectral uses [JSONPath Plus](https://www.npmjs.com/package/jsonpath-plus)). - The `then` property includes the `function` type and options that tells Spectral how to apply the function to the JSON or YAML file, and make sure that the rule is being followed or not. Spectral has a set of [built-in functions](../reference/functions.md) such as `truthy` or `pattern`, which can be used to power rules. diff --git a/docs/guides/4-custom-rulesets.md b/docs/guides/4-custom-rulesets.md index 12044b08b..a79132f34 100644 --- a/docs/guides/4-custom-rulesets.md +++ b/docs/guides/4-custom-rulesets.md @@ -10,10 +10,10 @@ There are five properties that can be used at the root level of a ruleset: - `rules` (required): An array of rules. See [Rules](./4a-rules.md) for more details. - `extends` (optional): A reference to other rulesets. Used to extend and customize existing rulesets. See [Extends](./4b-extends.md) for more details. -- `formats` (optional): The format that the ruleset should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](#formats) for more details. +- `formats` (optional): The format that the ruleset should apply to. For example, `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](#formats) for more details. - `documentationUrl` (optional): A URL that contains more information about the ruleset and rules in it. Can help provide users more context on why the ruleset exists and how it should be used. See [Documentation URL](#documentation-url) for more details. - `parserOptions` (optional): Can be used to tune the severity of duplicate keys or invalid values in your ruleset. See [Parsing Options](#parsing-options) for more details. -- `aliases` (optional): An array of key-value pairs that can be used to define commonly used JSONPath expressions, to be reused across a ruleset. See [Aliases](./4c-aliases.md) for more details. +- `aliases` (optional): An array of key-value pairs that can be used to define commonly used JSONPath expressions to be reused across a ruleset. See [Aliases](./4c-aliases.md) for more details. - `overrides` (optional): Can be used to customize which formats, files, or parts of files, that a ruleset should be applied to. See [Overrides](./4d-overrides.md) for more details. Rules are the most important part of a ruleset. For more details on rules and its properties, see [Rules](./4a-rules.md). @@ -41,26 +41,7 @@ Formats are an optional way to specify which API description formats a rule, or - `json-schema-2019-09` (`$schema` says this is JSON Schema 2019-09) - `json-schema-2020-12` (`$schema` says this is JSON Schema 2020-12) -Specifying the format is optional, so you can completely ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. If you'd like to use one ruleset for multiple formats, the `formats` key is here to help. - -```yaml -rules: - oas3-api-servers: - description: "OpenAPI `servers` must be present and non-empty array." - formats: ["oas3"] - given: "$" - then: - field: servers - function: schema - functionOptions: - schema: - items: - type: object - minItems: 1 - type: array -``` - -Specifying the format is optional, so you can completely ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. +Specifying the format is optional, so you can ignore this if all the rules you are writing apply to any document you lint, or if you have specific rulesets for different formats. If you'd like to use one ruleset for multiple formats, use the `formats` key. Formats can be specified at the ruleset level: @@ -140,7 +121,7 @@ rules: -If you do not care about duplicate keys or invalid values (such as non-string mapping keys in YAML), you can tune their severity using the `parserOptions` setting. +If you don't care about duplicate keys or invalid values (such as non-string mapping keys in YAML), you can tune their severity using the `parserOptions` setting. ```yaml extends: spectral:oas diff --git a/docs/guides/4a-rules.md b/docs/guides/4a-rules.md index 46e8f8791..42d7bab31 100644 --- a/docs/guides/4a-rules.md +++ b/docs/guides/4a-rules.md @@ -24,7 +24,7 @@ Rules can have the following properties: - `given` (required): The part of the document the rule should be applied to. Uses the [JSONPath](https://goessner.net/articles/JsonPath/index.html) syntax. - `then` (required): Describes which function should be applied to the `given` part of the document. Can be used with a [core function](../reference/functions.md) or [custom function](./5-custom-functions.md). - `description` (optional): A short description of the rule. -- `message` (optional): A message that will be displayed in the `spectral lint` output. Can be customized to use placeholder values that are evaluated at runtime, such as `{{description}}` or `{{error}}`. +- `message` (optional): A message that's displayed in the `spectral lint` output. Can be customized to use placeholder values that are evaluated at runtime, such as `{{description}}` or `{{error}}`. - `severity` (optional): The severity of the rule. Used to differentiate between rules that must be followed (`error`) and warnings or hints. Default value is `warn`. - `formats` (optional): The format that the rule should apply to. For example `oas3` for any OpenAPI v3.x descriptions. Can be applied at the ruleset and/or rule level. See [Formats](./4-custom-rulesets.md#formats) for more details. - `recommended` (optional): Recommended is a property that is used when extending a ruleset, where users can define if they would like to enforce all rules (`recommended` set to `true` and `false`) or only recommended rules (`recommended` set to `true`). Recommended can be used to help slowly roll out a ruleset across API landscapes with a lot of legacy APIs. Default value is `true`. See [Recommended](./4e-recommended.md) for more details. @@ -34,9 +34,9 @@ Let's look at all the properties that can be used for a rule. ### Given -The `given` property is conceptually quite like a selector in CSS, in that it picks the part of the document to apply rules to. +The `given` property is conceptually quite like a selector in CSS, in that it indicates the part of the document to apply rules to. -It has a specific syntax known as [JSONPath](https://goessner.net/articles/JsonPath/index.html), which if you are familiar with XPath is quite similar. JSONPath is not yet a standard (it [will be](https://tools.ietf.org/html/draft-normington-jsonpath-00) someday), and has a few competing implementations. Spectral uses [nimma](https://www.npmjs.com/package/nimma) as its main implementation, and sometimes resorts to [jsonpath-plus](https://www.npmjs.com/package/jsonpath-plus) to ensure a good backwards-compatibility. +It has a specific syntax known as [JSONPath](https://goessner.net/articles/JsonPath/index.html), which if you are familiar with XPath is quite similar. JSONPath is not yet a standard (it [will be](https://tools.ietf.org/html/draft-normington-jsonpath-00) someday), and has a few competing implementations. Spectral uses [nimma](https://www.npmjs.com/package/nimma) as its main implementation, and sometimes resorts to [jsonpath-plus](https://www.npmjs.com/package/jsonpath-plus) to ensure good backwards-compatibility. Both of them support all the main JSONPath functionality and a little bit more, but this syntax may differ slightly from other JSONPath implementations. Your `given` value can be a string containing any valid JSONPath expression, or an array of expressions to apply a rule to multiple parts of a document. @@ -56,7 +56,7 @@ then: function: truthy ``` -The `field` keyword is optional and is used to apply the function to a specific property in an object. If omitted the function will be applied to the entire target of the `given` JSONPath. The value can also be `@key` to apply the rule to the keys of an object. +The `field` keyword is optional and is used to apply the function to a specific property in an object. If omitted, the function will be applied to the entire target of the `given` JSONPath. The value can also be `@key` to apply the rule to the keys of an object. ```yaml given: "$.responses" @@ -95,7 +95,7 @@ contact-properties: ### Message -To help you create meaningful messages for results, Spectral comes with a couple of placeholders that are evaluated at runtime. +To help you create meaningful messages for results, Spectral comes with placeholders that are evaluated at runtime. - `{{error}}` - the error returned by function - `{{description}}` - the description set on the rule @@ -121,20 +121,13 @@ message: "{{path}} cannot point at remote reference" ### Severity -The `severity` keyword is optional and can be `error`, `warn`, `info`, or `hint`. +The `severity` keyword is optional and can be `error`, `warn`, `info`, `hint`, or `off`. The default value is `warn`. ### Resolved -By default, Spectral processes each rule on a "resolved" document (a file where -all `$ref` JSON Schema references have been replaced with the objects they point -to). While this is typically the desired behavior, there are some use cases -where you may need to run a rule on the "raw" un-resolved document. - -For example, if you want to enforce conventions on the folder structure used for -[splitting up -documents](https://blog.stoplight.io/keeping-openapi-dry-and-portable?utm_medium=spectral&utm_source=github&utm_campaign=docs). +By default, Spectral processes each rule on a "resolved" document (a file where all `$ref` JSON Schema references have been replaced with the objects they point to). While this is typically the desired behavior, there are some use cases where you may need to run a rule on the "raw" un-resolved document (for example, if you want to enforce conventions on the folder structure used for [splitting up documents](https://blog.stoplight.io/keeping-openapi-dry-and-portable?utm_medium=spectral&utm_source=github&utm_campaign=docs)). If your rule needs to access the raw `$ref` reference values, you can set `resolved: false` to allow the rule to receive the raw un-resolved version of the document. Otherwise `resolved: true` is the default. diff --git a/docs/guides/4b-extends.md b/docs/guides/4b-extends.md index 2b091dce1..4e63112d0 100644 --- a/docs/guides/4b-extends.md +++ b/docs/guides/4b-extends.md @@ -15,7 +15,7 @@ extends: - some-npm-module # note that this would be treated as any other npm package, therefore it has to be placed under node_modules and have a valid package.json. ``` -The `extends` keyword can be combined with extra rules in order to extend and override rulesets. Learn more about that in [custom rulesets](../guides/4-custom-rulesets.md). +The `extends` keyword can be combined with extra rules to extend and override rulesets. Learn more about that in [custom rulesets](../guides/4-custom-rulesets.md). ## Modify Rules @@ -34,7 +34,7 @@ rules: This provides a new description, but anything can be changed. -If you're just looking to change the severity of the rule, there is a handy shortcut. +If you're just looking to change the severity of the rule, there's a handy shortcut. ## Change Rule Severity @@ -46,4 +46,4 @@ rules: operation-success-response: warn ``` -Available severity levels are `error`, `warn`, `info`, `hint`, and `off`. +See [Severity](./4a-rules.md#severity) for more details. diff --git a/docs/guides/4c-aliases.md b/docs/guides/4c-aliases.md index 3a906aca0..0a4e11627 100644 --- a/docs/guides/4c-aliases.md +++ b/docs/guides/4c-aliases.md @@ -1,7 +1,8 @@ ## Aliases Targeting certain parts of an OpenAPI spec is powerful but it can become cumbersome to write and repeat complex JSONPath expressions across various rules. -Define aliases for commonly used JSONPath expressions on a global level which can then be reused across the ruleset. + +Define aliases for commonly used JSONPath expressions on a global level and then reuse them across the ruleset. Aliases can be defined in an array of key-value pairs at the root level of the ruleset, or alternatively, within an override. diff --git a/docs/guides/4d-overrides.md b/docs/guides/4d-overrides.md index c51cdbdc0..fd11f140b 100644 --- a/docs/guides/4d-overrides.md +++ b/docs/guides/4d-overrides.md @@ -1,6 +1,6 @@ ## Overrides -Previously Spectral supported exceptions, which were limited in their ability to target particular rules on specific files or parts of files, or change parts of a rule. Overrides is the much more powerful version of exceptions, with the ability to customize ruleset usage for different files and projects without having to duplicate any rules. +Previously Spectral supported exceptions, which were limited in their ability to target particular rules on specific files or parts of files, or change parts of a rule. Overrides are the much more powerful version of exceptions, with the ability to customize ruleset usage for different files and projects without having to duplicate any rules. Overrides can be used to apply rulesets on: @@ -58,7 +58,7 @@ In the event of multiple matches, the order of definition takes place, with the ### Caveats -Please bear in mind that overrides are only applied to the _root_ documents. If your documents have any external dependencies, i.e. $refs, the overrides won't apply. +Overrides are only applied to the _root_ documents. If your documents have any external dependencies, i.e. $refs, the overrides won't apply. **Example:** diff --git a/docs/guides/4e-recommended.md b/docs/guides/4e-recommended.md index e579d02de..f19cc6d6f 100644 --- a/docs/guides/4e-recommended.md +++ b/docs/guides/4e-recommended.md @@ -14,7 +14,7 @@ Far more rules exist than just the recommended ones, there are various other rul extends: [[spectral:oas, all]] ``` -You can do this with your rulesets, and slide new rules in as not recommended for a while so that only the most interested active API designers/developers get them at first, then eventually roll them out to everyone if they are well received. +You can do this with your rulesets, and initially set new rules as "not recommended" so that the most interested active API designers/developers use them at first. Then, eventually roll them out to everyone if they are well received. ### Disabling Rules @@ -26,11 +26,11 @@ rules: operation-operationId-unique: off ``` -The example above will run all of the rules defined in the `spectral:oas` ruleset (rather than the default behavior that runs only the recommended ones), with one exception - we turned `operation-operationId-unique` off. +The example above runs all of the rules defined in the `spectral:oas` ruleset (rather than the default behavior that runs only the recommended ones), with one exception; `operation-operationId-unique` is set to off. ### Enabling Rules -Sometimes you might want to apply a limited number of rules from another ruleset. To do this, use the `extends` property with `off` as the second argument. This will avoid running any rules from the extended ruleset as they will all be disabled. Then you can pick and choose which rules you would like to enable. +Sometimes you might want to apply a limited number of rules from another ruleset. To do this, use the `extends` property with `off` as the second argument. This avoids running any rules from the extended ruleset as they will all be disabled. Then you can pick and choose which rules you would like to enable. ```yaml extends: [[spectral:oas, off]] @@ -38,4 +38,4 @@ rules: operation-operationId-unique: true ``` -The example above will only run the rule `operation-operationId-unique` that we enabled since we passed `off` to disable all rules by default when extending the `spectral:oas` ruleset. +The example above only runs the rule `operation-operationId-unique` that we enabled since we passed `off` to disable all rules by default when extending the `spectral:oas` ruleset. diff --git a/docs/guides/4f-js-rulesets.md b/docs/guides/4f-js-rulesets.md index baa597ee7..e07293a10 100644 --- a/docs/guides/4f-js-rulesets.md +++ b/docs/guides/4f-js-rulesets.md @@ -2,7 +2,11 @@ Spectral v6.0 added support for a JavaScript ruleset format, similar to the JSON and YAML formats. -This has a few benefits: it lets you explicitly load formats or rulesets to get control over versioning, you can load common functions from popular JS libraries, and in general feels a lot more welcoming to developers experienced with JavaScript, especially when it comes to working with custom functions. +This has a few benefits: + +- It lets you explicitly load formats or rulesets to get control over versioning. +- You can load common functions from popular JS libraries. +- It feels a lot more welcoming to developers experienced with JavaScript, especially when it comes to working with custom functions. **Example** @@ -20,15 +24,15 @@ npm install --save @stoplight/spectral-functions npm install --save @stoplight/spectral-formats ``` -Installing these packages is not required for creating a JavaScript ruleset, but we'll use them in our example to create some common rules used with Spectral and to target a specific OpenAPI format. +Installing these packages is not required for creating a JavaScript ruleset, but you'll use them in the example to create some common rules used with Spectral and to target a specific OpenAPI format. -Next, let's create a JavaScript file to hold our ruleset: +Next, create a JavaScript file to hold your ruleset: ``` touch spectral.js ``` -And inside the file, let's create a couple rules: +Inside the file, create a couple of rules: ```js import { truthy, undefined as pattern, schema } from "@stoplight/spectral-functions"; @@ -92,7 +96,7 @@ export default { }; ``` -For those of you using custom functions, the keywords `functions` & `functionOptions` have been removed, as they were designed to help Spectral find your functions. Now functions are passed as a variable, instead of using a string that contains the name like the JSON/YAML formats. +If you use custom functions, the keywords `functions` and `functionOptions` have been removed, as they were designed to help Spectral find your functions. Now functions are passed as a variable, instead of using a string that contains the name like the JSON/YAML formats. This code example should look fairly familiar for anyone who has used the JSON or YAML formats. The next steps for using this ruleset would be publishing it as an npm package, and then installing that package as part of your API project and referencing in your Spectral ruleset as: