spectral.yaml (658 lines of code) (raw):
extends: spectral:oas
functionsDir: './functions'
functions:
- consistent-response-body
- error-response
- has-header
- lro-response-schema
- naming-convention
- operation-id
- pagination-parameters
- operation-security
- pagination-response
- param-names
- param-names-unique
- param-order
- patch-content-type
- path-param-schema
- path-param-names
- put-request-and-response-body
- property-default-not-allowed
- readonly-in-response-schema
- security-definitions
- security-requirements
- schema-type-and-format
- unused-definition
- version-policy
rules:
info-contact: off
no-$ref-siblings: off
oas2-api-host: off
oas2-api-schemes: off
oas2-unused-definition: off
openapi-tags: off
operation-description: off
operation-tags: off
operation-tag-defined: off
# Note: The Spectral VSCode extension will not display "hint" messages, so
# use "info" rather than "hint".
az-additional-properties-and-properties:
description: Don't specify additionalProperties as a sibling of properties.
severity: warn
formats: ['oas2', 'oas3']
given: $..[?(@object() && @.type === 'object' && @.properties)]
then:
field: additionalProperties
function: falsy
az-additional-properties-object:
description: additionalProperties with type object is a common error.
severity: info
formats: ['oas2', 'oas3']
# This rule produces redundant errors if run on the resolved spec.
resolved: false
given: $..[?(@property == 'additionalProperties' && @.type == 'object' && @.properties == undefined)]
then:
function: falsy
az-api-version-enum:
description: The api-version parameter should not be an enum.
severity: warn
# oas3 support has broken - disable for now
formats: ['oas2']
given:
- $.paths[*].parameters.[?(@.name == 'api-version')]
- $.paths.*[get,put,post,patch,delete,options,head].parameters.[?(@.name == 'api-version')]
then:
field: enum
function: falsy
az-boolean-naming-convention:
description: Do not use "is" prefix in names of boolean values
severity: warn
formats: ['oas2','oas3']
given: $
then:
function: naming-convention
functionOptions:
type: boolean
notMatch: '^is[A-Z]'
az-consistent-response-body:
description: Ensure the get, put, and patch response body schemas are consistent.
message: '{{error}}'
severity: warn
formats: ['oas2']
given: $.paths.*
then:
function: consistent-response-body
az-default-response:
description: All operations should have a default (error) response.
message: Operation is missing a default response.
severity: warn
given: $.paths.*.*.responses
then:
field: default
function: truthy
az-datetime-naming-convention:
description: Use an "At" suffix in names of date-time values.
severity: warn
formats: ['oas2','oas3']
given: $
then:
function: naming-convention
functionOptions:
type: date-time
match: 'At$'
az-delete-response-codes:
description: A delete operation should have a 204 response.
message: A delete operation should have a `204` response.
severity: warn
formats: ['oas2','oas3']
# The responses object of a delete operation
given: $.paths[*].delete.responses
then:
function: schema
functionOptions:
schema:
oneOf:
- required: ['202']
- required: ['204']
not:
required: ['200']
az-error-code-response-header:
description: Error response should contain a x-ms-error-code header.
severity: warn
formats: ['oas2']
given:
- $.paths[*][*].responses[?(@property >= 400)]
- $.paths[*][*].responses["default"]
then:
function: schema
functionOptions:
schema:
type: object
required: ['headers']
properties:
headers:
type: object
required: ["x-ms-error-code"]
az-error-response:
description: Error response body should conform to Microsoft Azure API Guidelines.
message: '{{error}}'
severity: warn
formats: ['oas2']
given: $.paths[*][*].responses
then:
function: error-response
az-formdata:
description: Check for appropriate use of formData parameters.
severity: info
formats: ['oas2']
given: $.paths.*[get,put,post,patch,delete,options,head].parameters.[?(@.in == "formData")]
then:
function: falsy
az-header-disallowed:
description: Authorization, Content-type, and Accept headers should not be defined explicitly.
message: 'Header parameter "{{value}}" should not be defined explicitly.'
severity: warn
# oas3 support has broken - disable for now
formats: ['oas2']
given:
- $.paths[*].parameters.[?(@.in == 'header')]
- $.paths.*[get,put,post,patch,delete,options,head].parameters.[?(@.in == 'header')]
then:
function: pattern
field: name
functionOptions:
notMatch: '/^(authorization|content-type|accept)$/i'
az-lro-extension:
description: "Operations with a 202 response should specify `x-ms-long-running-operation: true`."
message: "Operations with a 202 response should specify `x-ms-long-running-operation: true`."
severity: warn
formats: ['oas2']
given: $.paths[*][*].responses[?(@property == '202')]^^
then:
field: x-ms-long-running-operation
function: truthy
az-lro-get-not-allowed:
description: Get operations should not be long-running.
severity: warn
formats: ['oas2','oas3']
given: $.paths[*].get.responses.202
then:
function: falsy
az-lro-patch-not-allowed:
description: Patch operations should not be long-running.
severity: warn
formats: ['oas2','oas3']
given: $.paths[*].patch.responses.202
then:
function: falsy
az-lro-put-response-codes:
description: Long-running PUT should not return a 202 response.
severity: warn
formats: ['oas2','oas3']
given: $.paths[*].put.responses.202
then:
function: falsy
az-lro-response-codes:
description: An operation that returns 202 should not return other 2XX responses.
severity: warn
formats: ['oas2','oas3']
# The responses object of an operation that includes a 202 response
# Exclude get, put and patch since the 202 for these will be flagged in other rules
given: $.paths[*].[post,delete].responses[?(@property == '202')]^
then:
function: schema
functionOptions:
schema:
not:
anyOf:
- required: ['200']
- required: ['201']
- required: ['204']
az-lro-response-headers:
description: A 202 response should include an Operation-Location response header.
message: A 202 response should include an Operation-Location response header.
severity: warn
formats: ['oas2']
given: $.paths[*][*].responses[?(@property == '202')]
then:
function: has-header
functionOptions:
name: Operation-location
az-lro-response-schema:
description: A 202 response should include a schema for the operation status monitor.
message: '{{error}}'
severity: warn
formats: ['oas2']
given: $.paths[*][*].responses[?(@property == '202')]
then:
function: lro-response-schema
az-204-no-response-body:
description: A 204 response should have no response body.
severity: warn
formats: ['oas2']
given: $.paths[*][*].responses.204
then:
field: schema
function: falsy
az-ms-client-flatten:
description: The use of x-ms-client-flatten extension is discouraged.
severity: warn
formats: ['oas2', 'oas3']
resolved: false
given: $..x-ms-client-flatten
then:
function: undefined
az-ms-enum-descriptions:
description: Include descriptions for all values in the x-ms-enum extension.
severity: warn
formats: ['oas2', 'oas3']
given: $..x-ms-enum
then:
function: schema
functionOptions:
schema:
type: object
properties:
values:
type: array
items:
type: object
required: ['value', 'description']
required: ['values']
az-ms-paths:
description: Don't use x-ms-paths except where necessary to support legacy APIs.
severity: warn
formats: ['oas2', 'oas3']
given: $.x-ms-paths
then:
function: falsy
az-nullable:
description: Avoid the use of x-nullable.
severity: warn
formats: ['oas2', 'oas3']
resolved: false
given: $..x-nullable
then:
function: undefined
az-operation-id:
description: OperationId should conform to Azure API Guidelines
message: '{{error}}'
severity: warn
given:
- $.paths.*[get,put,post,patch,delete,options,head]
then:
function: operation-id
az-operation-security:
description: Operation should have a security requirement or globally.
message: Operation should have a security requirement.
severity: warn
formats: ['oas2', 'oas3']
given: $.paths.*[get,put,post,patch,delete,options,head]
then:
function: operation-security
az-operation-summary-or-description:
description: Operation should have a summary or description.
message: Operation should have a summary or description.
severity: warn
given:
- $.paths[*][?( @property === 'get' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'put' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'post' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'patch' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'delete' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'options' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'head' && !@.summary && !@.description )]
- $.paths[*][?( @property === 'trace' && !@.summary && !@.description )]
then:
function: falsy
az-pagination-parameters:
description: Pagination parameters must conform to Azure guidelines.
message: '{{error}}'
severity: warn
formats: ['oas2']
given:
- $.paths.*[get,post]
then:
function: pagination-parameters
az-pagination-response:
description: An operation that returns a list that is potentially large should support pagination.
message: '{{error}}'
severity: warn
formats: ['oas2']
given:
- $.paths.*[get,post]
then:
function: pagination-response
az-pageable-post:
description: Post operations that specify x-ms-pageable are problematic.
severity: info
formats: ['oas2', 'oas3']
given:
- $.paths.*[post]
then:
field: x-ms-pageable
function: falsy
az-parameter-default-not-allowed:
description: A required parameter should not specify a default value.
severity: warn
# oas3 support has broken - restrict to oas2 for now
formats: ['oas2']
given:
- $.paths[*].parameters.[?(@.required)]
- $.paths.*[get,put,post,patch,delete,options,head].parameters.[?(@.required)]
then:
field: default
function: falsy
az-parameter-description:
description: All parameters should have a description.
message: Parameter should have a description.
severity: warn
# In oas3 the description might be within the schema -- should not flag those
formats: ['oas2']
given:
- $.paths[*].parameters.*
- $.paths.*[get,put,post,patch,delete,options,head].parameters.*
then:
field: description
function: truthy
az-parameter-names-convention:
description: Parameter names should conform to Azure naming conventions.
message: '{{error}}'
severity: warn
given:
- $.paths[*].parameters.*
- $.paths.*[get,put,post,patch,delete,options,head].parameters.*
then:
function: param-names
az-parameter-names-unique:
description: All parameter names for an operation should be case-insensitive unique.
message: '{{error}}'
severity: warn
formats: ['oas2', 'oas3']
given: $.paths[*]
then:
function: param-names-unique
az-parameter-order:
description: Path parameters must be in the same order as in the path.
message: '{{error}}'
severity: warn
formats: ['oas2', 'oas3']
given: $.paths
then:
function: param-order
# Patch request body content type should be application/merge-patch+json
az-patch-content-type:
description: The request body content type for patch operations should be JSON merge patch.
message: '{{error}}'
severity: warn
formats: ['oas2']
given: $
then:
function: patch-content-type
# Patch on a path that does not end in path parameter is uncommon.
az-patch-path:
description: Patch on a path that does not end with a path parameter is uncommon.
severity: info
formats: ['oas2', 'oas3']
given: $.paths[?(!@path.match(/\}']$/))]
then:
field: patch
function: falsy
# Static path segments should be kebab-case
az-path-case-convention:
description: Static path segments should be kebab-case.
message: Static path segments should be kebab-case.
severity: info
formats: ['oas2', 'oas3']
given: $.paths.*~
then:
function: pattern
functionOptions:
# Check each path segment individually and ignore param segments
# Note: the ':' is only allowed in the final path segment
match: '^(\/([a-z][a-z0-9-]+|{[^}]+}))*\/([a-z][a-z0-9-]+|{[^}]*})?(:[A-Za-z0-9]+)?$'
# DO limit your URLs characters to 0-9 A-Z a-z - . _ ~ :
az-path-characters:
description: Path should contain only recommended characters.
message: Path contains non-recommended characters.
severity: info
formats: ['oas2', 'oas3']
given: $.paths.*~
then:
function: pattern
functionOptions:
# Check each path segment individually and ignore param segments
# Note: the ':' is only allowed in the final path segment
match: '^(\/([0-9A-Za-z._~-]+|{[^}]+}))*\/([0-9A-Za-z._~-]+|{[^}]*})?(:[0-9A-Za-z._~-]+)?$'
az-path-parameter-names:
description: Path parameter names should be consistent across all paths.
message: '{{error}}'
severity: warn
formats: ['oas2', 'oas3']
given: $.paths
then:
function: path-param-names
az-path-parameter-schema:
description: 'Path parameter should be type: string and specify maxLength and pattern.'
message: '{{error}}'
severity: info
formats: ['oas2', 'oas3']
given:
- $.paths[*].parameters[?(@.in == 'path')]
- $.paths[*][get,put,post,patch,delete,options,head].parameters[?(@.in == 'path')]
then:
function: path-param-schema
az-post-201-response:
description: Using post for a create operation is discouraged.
message: Using post for a create operation is discouraged.
severity: warn
formats: ['oas2']
given: $.paths[*].post.responses
then:
field: '201'
function: falsy
az-property-default-not-allowed:
description: A required property should not specify a default value.
message: '{{error}}'
severity: warn
formats: ['oas2']
given:
- $.paths[*].[put,post,patch].parameters.[?(@.in == 'body')].schema
- $.paths[*].[get,put,post,patch,delete].responses[*].schema
then:
function: property-default-not-allowed
az-property-description:
description: All schema properties should have a description.
message: Property should have a description.
severity: warn
resolved: false
given: $..properties[?(@object() && @.$ref == undefined)]
then:
field: description
function: truthy
# https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#172-casing
az-property-names-convention:
description: Property names should be camel case.
message: Property name should be camel case.
severity: warn
# This rule can report false positives if run on the resolved spec.
# Issue: https://github.com/stoplightio/spectral/issues/1316
resolved: false
given: $..[?(@.type === 'object' && @.properties)].properties.*~
then:
function: casing
functionOptions:
type: camel
az-property-type:
description: All schema properties should have a defined type.
message: Property should have a defined type.
severity: warn
resolved: false
# Exclude properties that contains allOf or oneOf or anyOf to avoid false positives.
given: $..properties[?(@object() && @.$ref == undefined && @.allOf == undefined && @.oneOf == undefined && @.anyOf == undefined)]
then:
field: type
function: truthy
az-put-path:
description: Put on a path that does not end with a path parameter is uncommon.
severity: info
formats: ['oas2', 'oas3']
given: $.paths[*].put^~
then:
function: pattern
functionOptions:
match: '/\}$/'
az-put-request-and-response-body:
description: A PUT operation should use the same schema for the request and response body.
severity: info
formats: ['oas2']
# Run on the unresolved document so that we compare the $ref'ed schema
resolved: false
given: $.paths[*].put
then:
function: put-request-and-response-body
az-readonly-in-response-schema:
description: Properties in response-only schemas should not be marked as readOnly true
severity: warn
formats: ['oas2']
given: $.definitions[*]
then:
function: readonly-in-response-schema
az-request-body-not-allowed:
description: A get or delete operation must not accept a body parameter.
severity: error
formats: ['oas2']
given:
- $.paths[*].[get,delete].parameters[*]
then:
field: in
function: pattern
functionOptions:
notMatch: '/^body$/'
az-request-body-optional:
description: Flag optional request body -- common oversight.
message: The body parameter is not marked as required.
severity: info
formats: ['oas2']
given:
# Don't flag request body if it explicitly specifies required: false
- $.paths[*].[put,post,patch].parameters.[?(@.in == 'body' && @.required == undefined)]
then:
function: falsy
az-request-body-type:
description: Request body schema must not be a bare array.
severity: warn
formats: ['oas2']
given:
- $.paths[*].[put,post,patch].parameters.[?(@.in == 'body')].schema
then:
field: type
function: pattern
functionOptions:
notMatch: '/^array$/'
az-response-body-type:
description: Response body schema must not be a bare array.
severity: warn
formats: ['oas2', 'oas3']
given: $.paths[*][*][responses][*].schema
then:
field: type
function: pattern
functionOptions:
notMatch: '/^array$/'
az-schema-description-or-title:
description: All schemas should have a description or title.
message: Schema should have a description or title.
severity: warn
formats: ['oas2', 'oas3']
given:
- $.definitions[?(!@.description && !@.title)]
- $.components.schemas[?(!@.description && !@.title)]
then:
function: falsy
az-schema-names-convention:
description: Schema names should be Pascal case.
message: Schema name should be Pascal case.
severity: info
formats: ['oas2']
given: $.definitions.*~
then:
# Pascal case with optional "." separator
function: pattern
functionOptions:
match: '^([A-Z][a-z0-9]+\.?)*[A-Z][a-z0-9]+$'
az-schema-type-and-format:
description: Schema should use well-defined type and format.
message: '{{error}}'
severity: warn
formats: ['oas2']
given:
- $.paths[*].[put,post,patch].parameters.[?(@.in == 'body')].schema
- $.paths[*].[get,put,post,patch,delete].responses[*].schema
then:
function: schema-type-and-format
az-security-definition-description:
description: A security definition should have a description.
message: Security definition should have a description.
severity: warn
formats: ['oas2', 'oas3']
given:
- $.securityDefinitions[*]
- $.components.securitySchemes[*]
then:
field: description
function: truthy
az-security-definitions:
description: Security definitions must follow Azure conventions.
message: '{{error}}'
severity: warn
formats: ['oas2']
given: $
then:
function: security-definitions
az-security-requirements:
description: The security requirement should reference a defined security scheme.
message: '{{error}}'
severity: warn
# Drop oas3 format for now
formats: ['oas2']
given:
- $.security
- $.paths.*[get,put,post,patch,delete,options,head].security
then:
function: security-requirements
az-security-min-length:
description: Security property should specify at least one security requirement.
severity: warn
formats: ['oas2', 'oas3']
given:
- $.security
- $.paths.*[get,put,post,patch,delete,options,head].security
then:
function: length
functionOptions:
min: 1
# All success responses except 204 should define a response body
# ref: https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#1321-put
az-success-response-body:
description: All success responses except 204 should define a response body.
severity: warn
formats: ['oas2']
# list http methods explicitly to exclude head
# exclude 202 to avoid duplication with az-lro-response-schema rule
given: $.paths[*][get,put,post,patch,delete].responses[?(@property >= 200 && @property < 300 && @property != '202' && @property != '204')]
then:
field: schema
function: truthy
az-unused-definition:
description: Potentially unused definition has been detected.
severity: warn
formats: ['oas2']
resolved: false
given: $.definitions
then:
function: unused-definition
az-version-convention:
description: API version should be a date in YYYY-MM-DD format, optionally suffixed with '-preview'.
severity: error
formats: ['oas2', 'oas3']
given: $.info.version
then:
function: pattern
functionOptions:
match: '^\d\d\d\d-\d\d-\d\d(-preview)?$'
az-version-policy:
description: Specify API version using `api-version` query parameter, not in path.
message: '{{error}}'
severity: warn
formats: ['oas2']
given: $
then:
function: version-policy