Files
api-guidelines/.spectral.yml
2025-09-19 15:31:11 +02:00

492 lines
15 KiB
YAML

extends: [[spectral:oas, all], [spectral:asyncapi, all]]
# https://docs.stoplight.io/docs/spectral/4dec24461f3af-open-api-rules
# https://docs.stoplight.io/docs/spectral/1e63ffd0220f3-async-api-rules
documentationUrl: https://github.com/adidas/api-guidelines/blob/master/ruleset.md
rules:
operation-tags: off
operation-operationId: off
operation-success-response: error
# ----------------------------#
# Adidas OAS v2.0, v3.0 rules #
# ----------------------------#
adidas-paths-kebab-case:
description: All YAML/JSON paths MUST follow kebab-case
severity: warn
recommended: true
message: "{{property}} is not kebab-case: {{error}}"
given: $.paths[*]~
then:
function: pattern
functionOptions:
match: "^\/([a-z0-9]+(-[a-z0-9]+)*)?(\/[a-z0-9]+(-[a-z0-9]+)*|\/{.+})*$" # doesn't allow /asasd{asdas}sadas pattern or not closed braces
adidas-path-parameters-camelCase-alphanumeric:
description: Path parameters MUST follow camelCase
severity: warn
recommended: true
message: "{{property}} path parameter is not camelCase: {{error}}"
given: $..parameters[?(@.in == 'path')].name
then:
function: pattern
functionOptions:
match: "^[a-z][a-zA-Z0-9]+$"
adidas-definitions-camelCase-alphanumeric:
description: All YAML/JSON definitions MUST follow fields-camelCase and be ASCII alphanumeric characters or `_` or `$`.
severity: error
recommended: true
message: "{{property}} MUST follow camelCase and be ASCII alphanumeric characters or `_` or `$`."
given: $.definitions[*]~
then:
function: pattern
functionOptions:
match: "/^[a-z$_]{1}[A-Z09$_]*/"
adidas-properties-camelCase-alphanumeric:
description: All JSON Schema properties MUST follow fields-camelCase and be ASCII alphanumeric characters or `_` or `$`.
severity: error
recommended: true
message: "{{property}} MUST follow camelCase and be ASCII alphanumeric characters or `_` or `$`."
given: $.definitions..properties[*]~
then:
function: pattern
functionOptions:
match: "/^[a-z$_]{1}[A-Z09$_]*/"
adidas-headers-hyphenated-pascal-case:
description: All `HTTP` headers MUST use `Hyphenated-Pascal-Case` notation
severity: error
given: "$..parameters[?(@.in == 'header')].name"
message: "'HTTP' headers MUST follow 'Hyphenated-Pascal-Case' notation"
recommended: true
type: style
then:
function: pattern
functionOptions:
match: "/^([A-Z][a-z0-9]-)*([A-Z][a-z0-9])+/"
# ----------------------#
# Adidas OAS v2.0 rules #
# ----------------------#
adidas-oas2-protocol-https-only:
description: "ALL requests MUST go through `https` protocol only"
formats:
- oas2
recommended: true
severity: error
type: "style"
message: "Schemes MUST be https and no other value is allowed."
given: $
then:
field: schemes
function: schema
functionOptions:
schema:
type: array
items:
type: string
enum: ["https"]
maxItems: 1
adidas-oas2-request-support-json:
description: Every request SHOULD support `application/json` media type
formats:
- oas2
severity: warn
message: "{{description}}: {{error}}"
recommended: true
given: "$..consumes"
then:
function: schema
functionOptions:
schema:
type: array
contains:
type: string
enum:
- application/json
adidas-oas2-example-exists-in-parameters:
description: All models MUST have a valid example.
severity: error
recommended: true
formats:
- oas2
message: "{{ property }} MUST have a valid example."
given: "$..parameters..[?(@.in == 'body' && (@.example || @.schema.$ref))]"
then:
function: truthy
# example-exists-in-definitions covery by oas2-valid-media-example
adidas-oas2-response-success-hal: # schemes and/or produces
description: "All success responses MUST be of media type `application/hal+json`"
severity: error
given: $.paths..responses[?( @property >= 200 && @property < 300 && @property != 204)]
recommended: true
type: "style"
formats:
- oas2
message: "Response documents MUST follow application/hal+json: {{error}}"
then:
field: schema
function: schema
functionOptions:
schema:
$ref: "./supermodel/adidas/api/HAL.yaml"
adidas-oas2-response-error-problem: # schemas and/or produces
description: All error responses MUST be of media type `application/problem+json`
severity: error
formats:
- oas2
given: $.paths..responses[?( @property >= 400 && @property < 600 )]
recommended: true
type: "style"
message: "Error response document MUST follow application/problem+json: {{error}}"
then:
field: schema.example
function: schema
functionOptions:
schema:
$ref: "./supermodel/adidas/api/ProblemDetail.yaml"
# ----------------------#
# Adidas OAS v3.0 rules #
# ----------------------#
adidas-oas3-request-support-json:
description: Every request MUST support `application/json` media type
formats:
- oas3
recommended: true
severity: error
message: "{{description}}: {{error}}"
given: $.paths.[*].requestBody.content[?(@property.indexOf('json') === -1)]^
then:
function: falsy
# adidas-oas3-valid-example-in-parameters && adidas-oas3-valid-example-in-definitions covered by oas3-valid-media-example
adidas-oas3-protocol-https-only:
description: "ALL requests MUST go through `https` protocol only"
formats:
- oas3
recommended: true
severity: error
message: "Servers MUST be https and no other protocol is allowed."
given: $.servers..url
then:
function: pattern
functionOptions:
match: "/^https:/"
adidas-oas3-response-success-hal:
description: "All success responses MUST be of media type `application/hal+json` "
severity: error
given: $.paths..responses[?( @property >= 201 && @property < 300 && @property != 204)].content[*]~
recommended: true
formats:
- oas3
message: "Response documents MUST be of application/hal+json media types: {{error}}"
then:
function: enumeration
functionOptions:
values:
- application/hal+json
# sync and async patterns that can return hal OR problem+json
adidas-oas3-response-success-OK:
description: "All success responses MUST be of media type `application/hal+json` or `application/problem+json`"
severity: error
given: $.paths..responses[?( @property == 200 )].content[*]~
recommended: true
formats:
- oas3
message: "Response documents MUST be of application/hal+json or application/problem+json media types: {{error}}"
then:
function: enumeration
functionOptions:
values:
- application/hal+json
- application/problem+json
adidas-oas3-response-success-hal-body: # schemes and/or produces
description: "All success responses MUST follow `application/hal+json` schema"
severity: error
given: $.paths..responses[?( @property == 200 && @property < 300 && @property != 204)].content[?(@property === "application/hal+json")]
recommended: true
type: "style"
formats:
- oas3
message: "Response documents MUST follow application/hal+json schema: {{error}}"
then:
field: schema
function: schema
functionOptions:
schema:
$ref: "./supermodel/adidas/api/HAL.yaml"
# API Maturity Matrix Rule
# 1/1-1/01
adidas-oas3-no-get-request-body:
description: "GET requests MUST NOT have a request body."
severity: error
recommended: true
formats:
- oas2
- oas3
given: "$.paths[*].get.requestBody"
then:
function: falsy
message: "{{description}}: {{error}}"
# 1/1-1/02
adidas-oas3-not-post-to-get-info:
description: "POST requests SHOULD NOT be used for retrieving information. Use GET instead."
severity: error
recommended: true
formats:
- oas2
- oas3
given: "$.paths[*].post"
then:
field: "summary"
function: pattern
functionOptions:
notMatch: "(retrieve|fetch|get|read)"
message: "{{description}}: {{error}}"
# 1/1-1/03
adidas-oas3-put-with-request-body:
description: "PUT requests MUST have a request body."
severity: error
recommended: true
formats:
- oas2
- oas3
given: "$.paths[*].put"
then:
field: "requestBody"
function: truthy
message: "{{description}}: {{error}}"
# 1/1-1/04
adidas-oas3-delete-with-request-body:
description: "DELETE requests MUST NOT have a request body."
severity: error
recommended: true
formats:
- oas2
- oas3
given: "$.paths[*].delete.requestBody"
then:
function: falsy
message: "{{description}}: {{error}}"
# 1/1-1/05
adidas-oas3-no-verbs-in-paths:
description: "API paths MUST be resource-focused and MUST NOT include verbs like 'get', 'update', 'create', or 'delete'."
severity: warn
recommended: true
formats:
- oas2
- oas3
message: "Path '{{path}}' includes a verb (e.g., 'get', 'update', 'create', 'delete'). API paths SHOULD be resource-focused."
given: $.paths[*]~
then:
function: pattern
functionOptions:
notMatch: "/\\b(get|update|create|delete|fetch|retrieve)\\b/"
# 1/1-1/06
adidas-oas3-real-like-examples:
description: "API design SHOULD include real-like examples for request and response definitions."
severity: warn
recommended: true
formats:
- oas2
- oas3
message: "The {{property}} SHOULD include a real-like example. Add realistic examples to improve API usability."
given: "$..[?(@.example || @.examples)]"
then:
field: "example"
function: truthy
# 1/1-1/07
adidas-oas3-stable-semantic-version:
description: "The API contract MUST have a stable version and MUST follow semantic versioning (e.g., '1.0.0'). Words like 'SNAPSHOT' or 'RELEASE' are not allowed."
severity: error
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$.info.version"
then:
function: pattern
functionOptions:
match: "^(?!.*\\b(SNAPSHOT|RELEASE)\\b)(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
# 1/1-1/08
adidas-oas3-security-section-required:
description: "The API contract MUST include a 'security' section at the root level."
severity: error
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$"
then:
field: "security"
function: truthy
adidas-oas3-components-required:
description: "The API contract MUST include a 'components' section."
severity: error
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$"
then:
field: "components"
function: truthy
adidas-oas3-security-schemes-required:
description: "The API contract MUST include a 'securitySchemes' subsection under the 'components' section."
severity: error
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$.components"
then:
field: "securitySchemes"
function: truthy
# 1/1-1/09
adidas-oas3-x-leanixid-required:
description: "The API contract SHOULD include a custom field 'x-leanixid' in the 'info' section."
severity: warn
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$.info"
then:
field: "x-leanixid"
function: truthy
# 1/1-1/10
adidas-oas3-x-leanixid-uuid:
description: "The API contract SHOULD include a custom field 'x-leanixid' containing a valid UUID."
severity: warn
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$.info.x-leanixid"
then:
function: pattern
functionOptions:
match: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
# 1/1-1/10B
# adidas-oas3-x-leanixid-real:
# description: "The leanxid must be real in the adidas Leanix inventory."
# severity: error
# recommended: true
# formats:
# - oas2
# - oas3
# message: "{{description}}: {{error}}"
# given: "$.info.x-leanixid"
# then:
# function: customFunction
# 1/1-1/11
adidas-oas3-x-gateway-required:
description: "The API contract SHOULD include a custom field 'x-gateway' in the 'info' section."
severity: warn
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$.info"
then:
field: "x-gateway"
function: truthy
# 1/1-1/11B
adidas-oas3-x-gateway-required-enumeration:
description: "The 'x-gateway' property, if present, MUST have a value in the enumeration: kong, nginx, aws, akamai, sap, other."
severity: warn
recommended: true
formats:
- oas2
- oas3
given: "$"
then:
field: "x-gateway"
function: enumeration
functionOptions:
values:
- kong
- nginx
- aws
- akamai
- sap
- other
# 1/1-1/12
adidas-oas3-hypermedia-links-required:
description: "The API contract MAY include hypermedia links to represent the state of resources and be navigable."
severity: hint
recommended: true
formats:
- oas2
- oas3
message: "{{description}}: {{error}}"
given: "$.paths[*][*].responses[*]"
then:
field: "links"
function: truthy
# ---------------------------------------------------------------------------
# Not implemented
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# Other rules which are redundant or not feasible
# ---------------------------------------------------------------------------
# fields-date-iso8601:
# description: Date and time MUST follow [`ISO 8601` standard](https://www.iso.org/iso-8601-date-and-time-format.html)
# severity: error
# fields-language-iso639:
# description: Language codes MUST follow [`ISO 639` standard](https://www.iso.org/iso-639-language-codes.html)
# severity: error
# fields-country-iso3166:
# description: Country codes MUST follow [`ISO 3166 alpha-2` standard](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
# severity: error
# fields-currency-iso4217:
# description: Currency codes MUST follow [`ISO 4217` standard](https://en.wikipedia.org/wiki/ISO_4217)
# severity: error
# response-303-async-link-header:
# description: A successful and finished async api request returns `303` response code and sends the target resource location in the `Link` header
# severity: hint