OpenAPI document linting
TIP
The
Speakeasy VS Code
extension (opens in a new tab)
provides syntax highlighting and autocompletion for editing the
lint.yaml
file, as well as linting for OpenAPI documents and other supported file types.
In addition to running validation, Speakeasy lints OpenAPI documents to ensure stylistic validity. By default, the linter runs using a recommended set of rules, which can be extended with the available ruleset. Custom rules can also be written using the Spectral format.
The Speakeasy Linter offers:
- Linting and validation of OpenAPI 3.x documents
- Access to 70+ rules
- Quick start with five out-the-box rulesets:
speakeasy-recommended
,speakeasy-generation
,speakeasy-openapi
,vacuum
, andowasp
- Reconfiguration of Speakeasy default rules and rulesets
- Configuration of custom rulesets
- Definition of new rules using the Spectral rule format
- Support for custom functions written in Go and JavaScript
Usage
Three options are available for running linting:
- Run manually via the Speakeasy CLI:
speakeasy lint openapi -s openapi.yaml
- Integrate into a Speakeasy workflow:
workflowVersion: "1.0.0"speakeasyVersion: latestsources:api-source:inputs:- location: ./openapi.yaml
Running speakeasy run
lints the document as part of the workflow and generates an HTML report accessible from a link in the command output.
- Use the
Speakeasy VS Code extension (opens in a new tab) in the IDE.
By default, these options use the speakeasy-recommended
ruleset to ensure OpenAPI documents meet the Speakeasy quality bar.
Configuration
OpenAPI spec linting is fully configurable. Create custom rulesets by selecting from predefined sets or writing new rules. These custom linting rules work throughout the workflow.
Immediately before SDK generation, the speakeasy-generation
ruleset is always applied to ensure compatibility with the code generator.
Configure linting in a lint.yaml
document in the .speakeasy
folder. The .speakeasy
folder can be located in the same directory as the OpenAPI document, the working directory for running the speakeasy lint
or speakeasy run
commands, or the home directory.
Example linting configuration in a lint.yaml
file:
lintVersion: 1.0.0defaultRuleset: speakeasyBarRulesetrulesets:barRuleset:rulesets:- speakeasy-generation # Use the speakeasy-generation ruleset as a base- customRulesetrules:validate-enums: {severity: warn, # drop the severity of the `validate-enums` rule to avoid blocking the pipeline}customRuleset:rules:paths-kebab-case: # A custom rule following the spectral format for a ruledescription: Paths should be kebab-case.message: "{{property}} should be kebab-case (lower-case and separated with hyphens)"severity: warngiven: $.paths[*]~then:functionOptions:match: "^(\\/|[a-z0-9-.]+|{[a-zA-Z0-9_]+})+$"contact-properties:description: Contact object must have "name", "url", and "email".given: $.info.contactseverity: warnthen:- field: namefunction: truthy- field: urlfunction: truthy- field: emailfunction: truthy
A lint.yaml
document defines a collection of rulesets that can be chained together or used independently. Define any built-in Speakeasy rulesets, create new rules, modify existing rules, or remix available rules to suit specific needs.
Use rulesets in these ways:
- Set the
defaultRuleset
in thelint.yaml
to use by default. This ruleset applies when no ruleset is specified using thelint
command orworkflow.yaml
file. - Pass a ruleset name to the
lint
command with the-r
argument, for example,speakeasy lint openapi -r barRuleset -s openapi.yaml
. - Define the ruleset for a particular source in the
workflow.yaml
file.
workflowVersion: "1.0.0"speakeasyVersion: latestsources:api-source:inputs:- location: ./openapi.yamlruleset: barRuleset
Custom rules
Create custom rules most easily using the Spectral rule format (opens in a new tab), which defines the rule and its properties as an object.
This format works for overriding built-in rules or defining new rules.
For more complex rules beyond pattern matching or field existence checking, define custom Go or JavaScript functions.
Custom Go/JavaScript functions
Speakeasy linting builds on vacuum (opens in a new tab) and supports custom Go or JavaScript functions in rules. The vacuum documentation explains writing custom functions in JavaScript (opens in a new tab) and Go (opens in a new tab).
After creating custom functions, place them in a directory named functions
in the .speakeasy
folder (e.g. .speakeasy/functions/foo.js
).
Available rules
The rules available to the Speakeasy Linter are listed below and can be used in custom rulesets or to match and modify default rules in the 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 entries. |
operation-tags | warn | Operation tags are missing or empty. |
owasp-define-error-responses-401 | warn | OWASP API Security recommends defining schemas for all responses, even 401 Unauthorized |
oas2-anyOf | error | anyOf was introduced in OpenAPI 3.0, cannot be used in OpenAPI 2.0 specs |
owasp-define-error-responses-429 | warn | OWASP API Security recommends defining schemas for all responses, even 429 Too Many Requests . |
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, or 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 in OpenAPI 2.0 specs. |
operation-tag-defined | warn | Operation tags must be defined in global tags. |
oas3-example-external-check | warn | Examples cannot use 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 at either global or operation level. |
oas3-schema | error | OpenAPI 3.0 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 an operation when converted to field names. |
validate-composite-schemas | error | Ensure anyOf , allOf , and 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 HTTPS, meaning server URLs should begin https:// . |
owasp-jwt-best-practices | error | JWTs must explicitly declare support for RFC 8725 in the description. |
owasp-define-error-responses-500 | warn | OWASP API Security recommends defining schemas for all responses, even 500 Internal Server Error . |
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.0 specification is invalid. |
operation-success-response | warn | Operation must have at least one 2xx or 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 a unique operationId . |
validate-types | error | Ensure data types are valid for generation. |
validate-consts-defaults | warn | Ensure const and default values 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 a non-empty array. |
validate-anyof | warn | anyOf should only contain types that 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, for example, /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 with min or 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 for 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-name | error | Duplicate operation names can cause SDK method name collisions. An SDK method name combines two parts: group and methodName , forming sdk.{group}.{methodName}() . The methodName is derived from operationId but can be overridden with x-speakeasy-name-override ; if neither is provided, it falls back to a name generated from the HTTP path and HTTP method. The optional group comes from x-speakeasy-group ; if absent, tags may be used. |
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
The rulesets available to the Speakeasy Linter are listed below and can be chained in custom rules. These rulesets will be used by default when custom linting configuration is not provided.
speakeasy-recommended
The Speakeasy Linter uses the speakeasy-recommended
ruleset by default when no custom ruleset is provided. This ruleset is recommended to ensure OpenAPI documents meet the Speakeasy quality bar.
Rule ID |
---|
duplicate-schema-name |
duplicate-operation-name |
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. This set of rules must pass to successfully generate an SDK from an OpenAPI document. This ruleset can’t be overridden or reconfigured when using the generator.
Use the speakeasy-generation
ruleset as appropriate to configure the linter to ensure an OpenAPI document is ready for generation.
Rule ID |
---|
duplicate-schema-name |
duplicate-operation-name |
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 recommended to ensure OpenAPI documents are generally valid and ready to be used by most 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. This set of rules is recommended to ensure OpenAPI documents meet the vacuum 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 recommended to ensure OpenAPI documents meet 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 |