OpenAPI document linting

Info Icon

TIP

The  Visual Studio Code logo  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, 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. You can also write custom rules using the Spectral format.

With the Speakeasy Linter, you can:

  • Lint and validate OpenAPI 3.x documents.
  • Choose from 70+ rules.
  • Get started quickly with five out-the-box rulesets, including speakeasy-recommended, speakeasy-generation, speakeasy-openapi, vacuum, and owasp.
  • Reconfigure the Speakeasy default rules and rulesets.
  • Configure custom rulesets.
  • Define new rules using the Spectral rule format.
  • Provide custom functions written in Go and JavaScript for custom rules.

Usage

There are three options for running linting:

  1. Run manually via the Speakeasy CLI:
speakeasy lint openapi -s openapi.yaml
  1. Integrate into your Speakeasy workflow:
workflowVersion: "1.0.0"
speakeasyVersion: latest
sources:
my-source:
inputs:
- location: ./openapi.yaml

Running speakeasy run will lint your document as part of the workflow and generate an HTML report that you can access from a link in the command output.

  1. Use the Visual Studio Code logo Speakeasy VS Code extension (opens in a new tab) in your IDE.

By default, these options use the speakeasy-recommended ruleset to ensure your OpenAPI document meets the Speakeasy quality bar.

Configuration

The linting of an OpenAPI spec is fully configurable. You can create a custom ruleset by selecting from our predefined sets or writing your own rules. These custom linting rules can be used throughout your workflow.

However, immediately before SDK generation, the speakeasy-generation ruleset is always used 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 you run the speakeasy lint or speakeasy run commands from, or the home directory.

Here is an example of linting configuration in a lint.yaml file:

lintVersion: 1.0.0
defaultRuleset: speakeasyBarRuleset
rulesets:
barRuleset:
rulesets:
- speakeasy-generation # Use the speakeasy-generation ruleset as a base
- ourRuleset
rules:
validate-enums: {
severity: warn, # drop the severity 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 collection of rulesets that can be chained together or used independently. You can define any built-in Speakeasy rulesets, define new rules, modify existing rules, or remix the available rules to suit your needs.

Rulesets can be used in various ways:

  1. Set the defaultRuleset in your lint.yaml to the ruleset you want to use by default. The default ruleset will be used if a ruleset is not specified using the lint command or workflow.yaml file.
  2. Pass a ruleset name to the lint command with the -r argument, for example, speakeasy lint openapi -r barRuleset -s openapi.yaml.
  3. Define the ruleset to use for a particular source in your workflow.yaml file.
workflowVersion: "1.0.0"
speakeasyVersion: latest
sources:
my-source:
inputs:
- location: ./openapi.yaml
ruleset: barRuleset

Custom rules

The easiest way to create a custom rule is to use the Spectral rule format (opens in a new tab), which is an object that defines the rule and its properties.

Use this format to override built-in rules or define new rules.

For rules that are more complex than matching a pattern or checking that a field exists, you can define a custom Go or JavaScript function in your rule.

Speakeasy linting is built on top of vacuum (opens in a new tab) and allows you to use custom Go or JavaScript functions in rules. The vacuum documentation provides instructions for writing custom functions in JavaScript (opens in a new tab) and Go (opens in a new tab).

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 IDDefault SeverityDescription
openapi-tags-alphabeticalinfoTags must be in alphabetical order.
tag-descriptionwarnTag must have a description defined.
no-$ref-siblingserror$ref values cannot be placed next to other properties (like a description).
oas3-unused-componentwarnCheck for unused components and bad references.
owasp-auth-insecure-schemeserrorAuthentication scheme is considered outdated or insecure.
no-http-verbs-in-pathwarnPath segments must not contain an HTTP verb.
operation-4xx-responsewarnMake sure operations return at least one 4xx error response to help with bad requests.
duplicated-entry-in-enumerrorEnum values must not have duplicate entries.
operation-tagswarnOperation tags are missing or empty.
owasp-define-error-responses-401warnOWASP API Security recommends defining schemas for all responses, even 401 Unauthorized
oas2-anyOferroranyOf was introduced in OpenAPI 3.0, cannot be used in OpenAPI 2.0 specs
owasp-define-error-responses-429warnOWASP API Security recommends defining schemas for all responses, even 429 Too Many Requests.
owasp-no-credentials-in-urlerrorURL parameters must not contain credentials such as API key, password, or secret.
duplicate-tagerrorTag names must be unique when converted to class, field, or file names.
validate-parameterserrorValidate parameters are unique and have a non-empty name property when converted to field names.
oas2-operation-formData-consume-checkwarnOperations with in: formData parameter must include application/x-www-form-urlencoded or multipart/form-data in their consumes property.
oas2-discriminatorerrorDiscriminators are used correctly in schemas.
oas2-operation-security-definederrorsecurity values must match a scheme defined in securityDefinitions.
oas2-oneOferroroneOf was introduced in OpenAPI 3.0, cannot be used in OpenAPI 2.0 specs.
operation-tag-definedwarnOperation tags must be defined in global tags.
oas3-example-external-checkwarnExamples cannot use value and externalValue together.
oas2-api-hostinfoOpenAPI host must be present and a non-empty string.
owasp-protection-global-unsafeerrorAPI should be protected by a security rule at either global or operation level.
oas3-schemaerrorOpenAPI 3.0 specification is invalid.
path-paramserrorPath parameters must be defined and valid.
owasp-string-limiterrorString size should be limited to mitigate resource exhaustion attacks.
owasp-no-http-basicerrorSecurity scheme uses HTTP Basic. Use a more secure authentication method like OAuth 2.0.
oas2-host-not-examplewarnHost URL should not point at example.com.
validate-enumserrorValidate enums are valid for type generation.
validate-pathserrorValidate paths conform to RFC 3986.
duplicate-propertieserrorProperty names must be unique and not empty within an operation when converted to field names.
validate-composite-schemaserrorEnsure anyOf, allOf, and oneOf don’t contain duplicate references.
owasp-protection-global-unsafe-strictinfoCheck if the operation is protected at operation level. Otherwise, check the global security property.
owasp-security-hosts-https-oas3errorAll server interactions MUST use HTTPS, meaning server URLs should begin https://.
owasp-jwt-best-practiceserrorJWTs must explicitly declare support for RFC 8725 in the description.
owasp-define-error-responses-500warnOWASP API Security recommends defining schemas for all responses, even 500 Internal Server Error.
description-duplicationinfoDescription duplication check.
no-script-tags-in-markdownerrorMarkdown descriptions must not have <script> tags.
owasp-rate-limit-retry-aftererrorEnsure that any 429 response contains a Retry-After header.
oas3-valid-schema-examplewarnIf an example has been used, check the schema is valid.
typed-enumwarnEnum values must respect the specified type.
operation-operationIderrorEvery operation must contain an operationId.
operation-parameterserrorOperation parameters are unique and non-repeating.
validate-requestserrorValidate request content types are valid MIME types.
validate-documenterrorDocument must have a paths or webhooks object.
no-ambiguous-pathserrorPaths need to resolve unambiguously from one another.
oas3-api-serverswarnCheck for valid API servers definition.
info-contactwarnInfo section is missing contact details.
paths-kebab-casewarnPath segments must only use kebab case (no underscores or uppercase).
openapi-tagswarnTop-level spec tags must not be empty and must be an array.
owasp-array-limiterrorArray size should be limited to mitigate resource exhaustion attacks.
oas-schema-checkerrorAll document schemas must have a valid type defined.
license-urlinfoLicense should contain a URL.
oas2-schemaerrorOpenAPI 2.0 specification is invalid.
operation-success-responsewarnOperation must have at least one 2xx or 3xx response.
owasp-no-api-keys-in-urlerrorAPI key has been detected in a URL.
info-descriptionerrorInfo section is missing a description.
oas3-missing-examplewarnEnsure everything that can have an example contains one.
oas3-host-trailing-slashwarnServer URL should not contain a trailing slash.
owasp-string-restrictederrorString must specify a format, RegEx pattern, enum, or const.
owasp-no-additionalPropertieswarnBy default, JSON Schema allows additional properties, which can potentially lead to mass assignment issues.
contact-propertiesinfoContact details are incomplete.
validate-securityerrorValidate security schemes are correct.
operation-operationId-uniqueerrorEvery operation must have a unique operationId.
validate-typeserrorEnsure data types are valid for generation.
validate-consts-defaultswarnEnsure const and default values match their type.
operation-singular-tagwarnOperation cannot have more than a single tag defined.
oas2-api-schemeswarnOpenAPI host schemes must be present and a non-empty array.
validate-anyofwarnanyOf should only contain types that are compatible with each other.
duplicate-schemashintInline object schemas must be unique.
missing-exampleshintExamples should be provided where possible.
no-eval-in-markdownerrorMarkdown descriptions must not have eval() statements.
oas2-host-trailing-slashwarnHost URL should not contain a trailing slash.
owasp-no-numeric-idserrorUse random IDs that cannot be guessed. UUIDs are preferred.
duplicate-schema-nameerrorSchema names must be unique when converted to class names.
validate-responseserrorValidate response content types are valid MIME types.
path-not-include-queryerrorPath must not include query string.
path-declarations-must-existerrorPath parameter declarations must not be empty, for example, /api/{} is invalid.
owasp-constrained-additionalPropertieswarnBy default, JSON Schema allows additional properties, which can potentially lead to mass assignment issues.
operation-descriptionwarnOperation description checks.
owasp-integer-formaterrorIntegers should be limited to mitigate resource exhaustion attacks.
owasp-integer-limiterrorIntegers should be limited with min or max values to mitigate resource exhaustion attacks.
validate-deprecationerrorEnsure correct usage of x-speakeasy-deprecation-replacement and x-speakeasy-deprecation-message extensions.
validate-json-schemaerrorValidate OpenAPI document against JSON Schema.
validate-content-typeerrorValidate content type schemas.
owasp-define-error-validationwarnMissing error response for 400, 422, or 4XX. Ensure all errors are documented.
owasp-rate-limiterrorDefine proper rate limiting to avoid attackers overloading the API.
oas3-parameter-descriptionwarnParameter description checks.
oas3-host-not-example.comwarnServer URL should not point at example.com.
component-descriptionwarnComponent description check.
oas3-operation-security-definederrorsecurity values must match a scheme defined in components.securitySchemes.
path-keys-no-trailing-slashwarnPath must not end with a slash.
duplicate-operation-nameerrorDuplicate 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-licenseinfoInfo section should contain a license.
owasp-protection-global-safeinfoCheck if the operation is protected at operation level. Otherwise, check the global security property.
operation-operationId-valid-in-urlerroroperationId must use URL-friendly characters.
validate-serverserrorValidate servers, variables, and x-speakeasy-server-id extension.
validate-extensionserrorValidate x-speakeasy-globals extension usage.
oas2-unused-definitionwarnCheck for unused definitions and bad references.
oas2-parameter-descriptionwarnParameter description checks.

Available rulesets

The rulesets available to the Speakeasy Linter are listed below and can be chained in your 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 your OpenAPI document meets 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 your OpenAPI document is 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 your OpenAPI document meets 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 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