OpenAPI Document Linting
TIP
For editing the lint.yaml
file, Speakeasy's VSCode extension (opens in a new tab) provides syntax highlighting and autocompletion for the file,
in addition to linting for OpenAPI documents, and our other supported file types.
In addition to running validation, you can use Speakeasy to lint your OpenAPI documents to ensure they are stylistically valid. By default, the linter runs using a recommended set of rules, which you can optionally extend with the available ruleset. Additionally you may write your own custom rules using the Spectral format.
With the Speakeasy Linter, you can:
- Lint & validate OpenAPI 3.x documents
- Choose from 70+ rules
- Get started quickly with 5 out-of-the-box rulesets including
speakeasy-recommended
,speakeasy-generation
,speakeasy-openapi
,vacuum
&owasp
- Reconfigure Speakeasy's default rules & rulesets
- Configure custom rulesets
- Define new rules via the Spectral rule format
- Provide custom functions written in Go and JS for custom rules
Usage
There are three options for running linting:
- Run manually via the Speakeasy CLI:
speakeasy lint openapi -s openapi.yaml
- Integrate into your Speakeasy workflow:
workflowVersion: "1.0.0"speakeasyVersion: latestsources: my-source: inputs: - location: ./openapi.yaml
then running speakeasy run
will lint your document as part of the workflow.
This will generate a HTML report that you can find by clicking on the link output by the command.
- In your IDE via
Speakeasy's VSCode extension (opens in a new tab)
By default these options use the speakeasy-recommended
ruleset to ensure your OpenAPI document meets Speakeasy's quality bar.
Configuration
Linting of an OpenAPI spec is fully configurable. You may create a custom ruleset by picking & choosing from our pre-defined sets or writing you own rules. Your custom linting rules can be used throughout your workflow.
The only exception is immediately prior to SDK generation. In that case, the speakeasy-generation
ruleset is always used, to ensure compatibility with the code generator.
This is done through setting up a lint.yaml
document in your .speakeasy
folder, the folder can either live alongside your openapi document, or in the working directory you are running the speakeasy lint
or speakeasy run
commands from or in your home directory.
An example linting configuration (lint.yaml) is shown below:
lintVersion: 1.0.0defaultRuleset: speakeasyBarRulesetrulesets: barRuleset: rulesets: - speakeasy-generation # Use the speakeasy-generation ruleset as a base - ourRuleset rules: validate-enums: { severity: warn, # drop the serverity of the `validate-enums` rule as I don't want this to block the pipeline } ourRuleset: rules: paths-kebab-case: # A custom rule following the spectral format for a rule description: Paths should be kebab-case. message: "{{property}} should be kebab-case (lower-case and separated with hyphens)" severity: warn given: $.paths[*]~ then: functionOptions: match: "^(\\/|[a-z0-9-.]+|{[a-zA-Z0-9_]+})+$" 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
A lint.yaml
document defines a set of rulesets that can be chained together or used independently. These can define any of our built-in rulesets or any other rulesets defined in the document along with defining new rules to add or existing rules to modify or even just remixing our available rules to only run the ones you need.
Rulesets can be used in a number of different ways:
- Set the
defaultRuleset
in yourlint.yaml
to the ruleset you want to use by default when this file is present. This will be used if a ruleset is not specified using the other options below. - Pass the ruleset name to the
lint
command with the-r
argument for examplespeakeasy lint openapi -r barRuleset -s openapi.yaml
. - Define the ruleset to use for a particular source in your
workflow.yaml
file.
workflowVersion: "1.0.0"speakeasyVersion: latestsources: my-source: inputs: - location: ./openapi.yaml ruleset: barRuleset
Custom rules
The easiest way to define a custom rule is to use the Spectral rule format (opens in a new tab). This is an object that defines the rule and its properties.
This format can be used to override any of the builtin rules or to define new rules.
If you need to do anything more complex then matching a pattern or checking a field exists, then you can define a custom function in Go or JS and use that in your rule.
Speakeasy linting is built on top of Vacuum (opens in a new tab) and allows for provding custom functions to be used in rules. These can be written in Go or JS and then used in your rules. Documentation on how to write these functions can be found in the Vacuum documentation for JS (opens in a new tab) and Go (opens in a new tab)
Available Rules
Below is a list of all the available rules available to the Speakeasy Linter. These can be used in your custom rulesets or can be used to match and modify the default rules in your lint.yaml
file.
Rule ID | Default Severity | Description |
---|---|---|
openapi-tags-alphabetical | info | Tags must be in alphabetical order |
tag-description | warn | Tag must have a description defined |
no-$ref-siblings | error | $ref values cannot be placed next to other properties (like a description) |
oas3-unused-component | warn | Check for unused components and bad references |
owasp-auth-insecure-schemes | error | Authentication scheme is considered outdated or insecure |
no-http-verbs-in-path | warn | Path segments must not contain an HTTP verb |
operation-4xx-response | warn | Make sure operations return at least one 4xx error response to help with bad requests |
duplicated-entry-in-enum | error | Enum values must not have duplicate entry |
operation-tags | warn | Operation tags are missing/empty |
owasp-define-error-responses-401 | warn | OWASP API Security recommends defining schemas for all responses, even error: 401 |
oas2-anyOf | error | anyOf was introduced in OpenAPI 3.0, cannot be used un OpenAPI 2 specs |
owasp-define-error-responses-429 | warn | OWASP API Security recommends defining schemas for all responses, even error: 429 |
owasp-no-credentials-in-url | error | URL parameters must not contain credentials such as API key, password, or secret. |
duplicate-tag | error | Tag names must be unique when converted to class/field/file names |
validate-parameters | error | Validate parameters are unique and have a non-empty 'name' property when converted to field names |
oas2-operation-formData-consume-check | warn | Operations with in: formData parameter must include application/x-www-form-urlencoded or multipart/form-data in their consumes property. |
oas2-discriminator | error | discriminators are used correctly in schemas |
oas2-operation-security-defined | error | security values must match a scheme defined in securityDefinitions |
oas2-oneOf | error | oneOf was introduced in OpenAPI 3.0, cannot be used un OpenAPI 2 specs |
operation-tag-defined | warn | Operation tags must be defined in global tags. |
oas3-example-external-check | warn | Examples cannot use both value and externalValue together. |
oas2-api-host | info | OpenAPI host must be present and a non-empty string |
owasp-protection-global-unsafe | error | API should be protected by a security rule either at global or operation level. |
oas3-schema | error | OpenAPI 3 specification is invalid |
path-params | error | Path parameters must be defined and valid. |
owasp-string-limit | error | String size should be limited to mitigate resource exhaustion attacks. |
owasp-no-http-basic | error | Security scheme uses HTTP Basic. Use a more secure authentication method, like OAuth 2.0 |
oas2-host-not-example | warn | Host URL should not point at example.com |
validate-enums | error | Validate enums are valid for type generation |
validate-paths | error | Validate paths conform to RFC 3986 |
duplicate-properties | error | Property names must be unique and not empty within a operation when converted to field names |
validate-composite-schemas | error | Ensure anyOf-allOf-oneOf don't contain duplicate references |
owasp-protection-global-unsafe-strict | info | Check if the operation is protected at operation level. Otherwise, check the global security property |
owasp-security-hosts-https-oas3 | error | All server interactions MUST use the https protocol, meaning server URLs should begin https:// . |
owasp-jwt-best-practices | error | JWTs must explicitly declare support for RFC8725 in the description |
owasp-define-error-responses-500 | warn | OWASP API Security recommends defining schemas for all responses, even error: 500 |
description-duplication | info | Description duplication check |
no-script-tags-in-markdown | error | Markdown descriptions must not have <script> tags' |
owasp-rate-limit-retry-after | error | Ensure that any 429 response, contains a Retry-After header. |
oas3-valid-schema-example | warn | If an example has been used, check the schema is valid |
typed-enum | warn | Enum values must respect the specified type |
operation-operationId | error | Every operation must contain an operationId . |
operation-parameters | error | Operation parameters are unique and non-repeating. |
validate-requests | error | Validate request content types are valid mime types |
validate-document | error | Document must have a paths or webhooks object |
no-ambiguous-paths | error | Paths need to resolve unambiguously from one another |
oas3-api-servers | warn | Check for valid API servers definition |
info-contact | warn | Info section is missing contact details |
paths-kebab-case | warn | Path segments must only use kebab-case (no underscores or uppercase) |
openapi-tags | warn | Top level spec tags must not be empty, and must be an array |
owasp-array-limit | error | Array size should be limited to mitigate resource exhaustion attacks. |
oas-schema-check | error | All document schemas must have a valid type defined |
license-url | info | License should contain a URL |
oas2-schema | error | OpenAPI 2 specification is invalid |
operation-success-response | warn | Operation must have at least one 2xx or a 3xx response. |
owasp-no-api-keys-in-url | error | API Key has been detected in a URL |
info-description | error | Info section is missing a description |
oas3-missing-example | warn | Ensure everything that can have an example, contains one |
oas3-host-trailing-slash | warn | server URL should not contain a trailing slash |
owasp-string-restricted | error | String must specify a format , RegEx pattern , enum , or const |
owasp-no-additionalProperties | warn | By default JSON Schema allows additional properties, which can potentially lead to mass assignment issues. |
contact-properties | info | Contact details are incomplete |
validate-security | error | Validate security schemes are correct |
operation-operationId-unique | error | Every operation must have unique operationId . |
validate-types | error | Ensure data types are valid for generation |
validate-consts-defaults | warn | Ensure consts and defaults match their type |
operation-singular-tag | warn | Operation cannot have more than a single tag defined |
oas2-api-schemes | warn | OpenAPI host schemes must be present and non-empty array |
validate-anyof | warn | anyOf should only contain types which are compatible with each other |
duplicate-schemas | hint | Inline, object schemas must be unique |
missing-examples | hint | Examples should be provided where possible |
no-eval-in-markdown | error | Markdown descriptions must not have eval() statements' |
oas2-host-trailing-slash | warn | Host URL should not contain a trailing slash |
owasp-no-numeric-ids | error | Use random IDs that cannot be guessed. UUIDs are preferred |
duplicate-schema-name | error | Schema names must be unique when converted to class names |
validate-responses | error | Validate response content types are valid mime types |
path-not-include-query | error | Path must not include query string |
path-declarations-must-exist | error | Path parameter declarations must not be empty ex. /api/{} is invalid |
owasp-constrained-additionalProperties | warn | By default JSON Schema allows additional properties, which can potentially lead to mass assignment issues. |
operation-description | warn | Operation description checks |
owasp-integer-format | error | Integers should be limited to mitigate resource exhaustion attacks. |
owasp-integer-limit | error | Integers should be limited via min/max values to mitigate resource exhaustion attacks. |
validate-deprecation | error | Ensure correct usage of x-speakeasy-deprecation-replacement and x-speakeasy-deprecation-message extensions |
validate-json-schema | error | Validate OpenAPI document against JSON schema |
validate-content-type | error | Validate content type schemas |
owasp-define-error-validation | warn | Missing error response of either 400 , 422 or 4XX , Ensure all errors are documented. |
owasp-rate-limit | error | Define proper rate limiting to avoid attackers overloading the API. |
oas3-parameter-description | warn | Parameter description checks |
oas3-host-not-example.com | warn | Server URL should not point at example.com |
component-description | warn | Component description check |
oas3-operation-security-defined | error | security values must match a scheme defined in components.securitySchemes |
path-keys-no-trailing-slash | warn | Path must not end with a slash |
duplicate-operation-id | error | Operation IDs (including inferred) must be unique across all operations and tags, and overridden method names must be unique within tags when converted to method names |
info-license | info | Info section should contain a license |
owasp-protection-global-safe | info | Check if the operation is protected at operation level. Otherwise, check the global security property |
operation-operationId-valid-in-url | error | OperationId must use URL friendly characters |
validate-servers | error | Validate servers, variables and x-speakeasy-server-id extension |
validate-extensions | error | Validate x-speakeasy-globals extension usage |
oas2-unused-definition | warn | Check for unused definitions and bad references |
oas2-parameter-description | warn | Parameter description checks |
Available Rulesets
Below is a list of all the available rulesets available to the Speakeasy Linter. These can be chained in your custom rules but get used by default when a custom linting configuration is not provided.
speakeasy-recommended
The speakeasy-recommended
ruleset is the default ruleset used by the Speakeasy Linter when no custom ruleset is provided. It is a set of rules that are recommended to be used to ensure your OpenAPI document meets Speakeasy's quality bar.
Rule ID |
---|
duplicate-schema-name |
duplicate-operation-id |
duplicate-properties |
validate-anyof |
validate-document |
validate-enums |
validate-extensions |
validate-json-schema |
validate-parameters |
validate-requests |
validate-responses |
validate-composite-schemas |
validate-security |
validate-servers |
validate-types |
validate-paths |
validate-deprecation |
duplicate-tag |
validate-consts-defaults |
validate-content-type |
duplicate-schemas |
missing-examples |
path-params |
path-declarations-must-exist |
path-not-include-query |
oas3-operation-security-defined |
typed-enum |
no-eval-in-markdown |
no-script-tags-in-markdown |
operation-operationId-unique |
operation-success-response |
oas3-unused-component |
oas3-host-not-example.com |
operation-operationId |
duplicated-entry-in-enum |
operation-tag-defined |
speakeasy-generation
The speakeasy-generation
ruleset is used when generating an SDK from an OpenAPI document. It is a set of rules that must pass to be able to successfully generate an SDK from your OpenAPI document. This ruleset when using the generator can't be overridden or reconfigured.
But you can use it as you see fit when configuring the linter to ensure your document is ready for generation.
Rule ID |
---|
duplicate-schema-name |
duplicate-operation-id |
duplicate-properties |
validate-anyof |
validate-document |
validate-enums |
validate-extensions |
validate-json-schema |
validate-parameters |
validate-requests |
validate-responses |
validate-composite-schemas |
validate-security |
validate-servers |
validate-types |
validate-paths |
validate-deprecation |
duplicate-tag |
validate-consts-defaults |
validate-content-type |
path-params |
path-declarations-must-exist |
path-not-include-query |
oas3-operation-security-defined |
typed-enum |
no-eval-in-markdown |
no-script-tags-in-markdown |
operation-operationId-unique |
speakeasy-openapi
The speakeasy-openapi
ruleset is a minimal set of rules that are recommended to be used to ensure your OpenAPI is generally valid and ready to be used by a majority of the OpenAPI ecosystem.
Rule ID |
---|
validate-anyof |
validate-document |
validate-json-schema |
validate-parameters |
validate-requests |
validate-responses |
validate-composite-schemas |
validate-security |
validate-servers |
validate-types |
validate-paths |
validate-deprecation |
validate-consts-defaults |
validate-content-type |
duplicate-schemas |
missing-examples |
path-params |
path-declarations-must-exist |
path-not-include-query |
oas3-operation-security-defined |
typed-enum |
no-eval-in-markdown |
no-script-tags-in-markdown |
operation-operationId-unique |
operation-success-response |
oas3-unused-component |
oas3-host-not-example.com |
operation-operationId |
duplicated-entry-in-enum |
operation-tag-defined |
vacuum
The vacuum
ruleset is provided by the Vacuum project (opens in a new tab) which the Speakeasy Linter is built on top of. It is a set of rules that are recommended to be used to ensure your OpenAPI document meets Vacuum's quality bar.
Rule ID |
---|
operation-success-response |
operation-operationId-unique |
operation-operationId |
operation-parameters |
operation-singular-tag |
operation-tag-defined |
path-params |
contact-properties |
info-contact |
info-description |
info-license |
license-url |
openapi-tags-alphabetical |
openapi-tags |
operation-tags |
operation-description |
component-description |
operation-operationId-valid-in-url |
path-declarations-must-exist |
path-keys-no-trailing-slash |
path-not-include-query |
tag-description |
no-$ref-siblings |
oas3-unused-component |
oas2-unused-definition |
oas2-api-host |
oas2-api-schemes |
oas2-discriminator |
oas2-host-not-example |
oas3-host-not-example.com |
oas2-host-trailing-slash |
oas3-host-trailing-slash |
oas2-parameter-description |
oas3-parameter-description |
oas3-operation-security-defined |
oas2-operation-security-defined |
typed-enum |
duplicated-entry-in-enum |
no-eval-in-markdown |
no-script-tags-in-markdown |
description-duplication |
oas3-api-servers |
oas2-operation-formData-consume-check |
oas2-anyOf |
oas2-oneOf |
no-ambiguous-paths |
no-http-verbs-in-path |
paths-kebab-case |
operation-4xx-response |
oas2-schema |
oas3-schema |
oas3-valid-schema-example |
oas3-missing-example |
oas3-example-external-check |
oas-schema-check |
owasp
The owasp
ruleset is a set of rules that are recommended to be used to ensure your OpenAPI document meets the Open Worldwide Application Security Project (OWASP) (opens in a new tab) quality bar.
Rule ID |
---|
owasp-protection-global-unsafe |
owasp-protection-global-unsafe-strict |
owasp-protection-global-safe |
owasp-define-error-responses-401 |
owasp-define-error-responses-500 |
owasp-rate-limit |
owasp-rate-limit-retry-after |
owasp-define-error-responses-429 |
owasp-array-limit |
owasp-jwt-best-practices |
owasp-auth-insecure-schemes |
owasp-no-numeric-ids |
owasp-no-http-basic |
owasp-define-error-validation |
owasp-no-api-keys-in-url |
owasp-no-credentials-in-url |
owasp-string-limit |
owasp-string-restricted |
owasp-integer-format |
owasp-integer-limit |
owasp-no-additionalProperties |
owasp-constrained-additionalProperties |
owasp-security-hosts-https-oas3 |