# Spotlight Rules — spotlight-recommended ruleset (verbatim) # generated: # method: searched # source: https://raw.githubusercontent.com/api-commons/spotlight-validator/main/rules/spotlight-recommended.yaml # note: Published by the Spotlight Rules project (api-commons/spotlight-validator, CNAME # validator.spotlight-rules.com). Compiled by Spotlight from public Spectral rulesets; # each rule carries source:* / category:* / format:* tags for attribution. Body below is # byte-for-byte as served; only these comment lines were prepended. description: Spotlight best-of-breed API governance ruleset, compiled from public Spectral rulesets. Select rules with tags (source:*, category:*, format:*). documentationUrl: https://github.com/api-commons/spotlight-validator extends: - - spotlight:oas - recommended rules: path-segments-kebab-case: description: "All YAML/JSON paths MUST follow kebab-case. It requires the targeted value to match the pattern `^/([a-z0-9]+(-[a-z0-9]+)*)?(/[a-z0-9]+(-[a-z0-9]+)*|/{.+})*$` (evaluated at `$.paths[*]~`). Severity: warn." 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]+)*|/{.+})*$ tags: - source:adidas - format:openapi - spec:paths - experience:naming - experience:consistency path-parameters-camel-case: description: "Path parameters MUST follow camelCase. It requires the targeted value to match the pattern `^[a-z][a-zA-Z0-9]+$` (evaluated at `$..parameters[?(@.in == 'path')].name`). Severity: warn." 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]+$ tags: - source:adidas - format:openapi - spec:parameters - experience:naming - experience:consistency schema-definitions-camel-case: description: "All YAML/JSON definitions MUST follow fields-camelCase and be ASCII alphanumeric characters or `_` or `$`. It requires the targeted value to match the pattern `/^[a-z$_]{1}[A-Z09$_]*/` (evaluated at `$.definitions[*]~`). Severity: error." 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$_]*/ tags: - source:adidas - format:openapi - spec:document - experience:naming - experience:consistency schema-properties-camel-case: description: "All JSON Schema properties MUST follow fields-camelCase and be ASCII alphanumeric characters or `_` or `$`. It requires the targeted value to match the pattern `/^[a-z$_]{1}[A-Z09$_]*/` (evaluated at `$.definitions..properties[*]~`). Severity: error." 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$_]*/ tags: - source:adidas - format:openapi - spec:schemas - experience:naming - experience:consistency header-names-hyphenated-pascal-case: description: "All `HTTP` headers MUST use `Hyphenated-Pascal-Case` notation. It requires the targeted value to match the pattern `/^([A-Z][a-z0-9]-)*([A-Z][a-z0-9])+/` (evaluated at `$..parameters[?(@.in == 'header')].name`). Severity: error." 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])+/ tags: - source:adidas - format:openapi - spec:parameters - spec:headers - experience:naming - experience:consistency - source:sps-commerce request-support-json-media-type: description: "Every request MUST support `application/json` media type. It requires the targeted value to be absent or empty (evaluated at `$.paths.[*].requestBody.content[?(@property.indexOf('json') === -1)]^`). Severity: error." formats: - oas3 recommended: true severity: error message: "{{description}}: {{error}}" given: $.paths.[*].requestBody.content[?(@property.indexOf('json') === -1)]^ then: function: falsy tags: - source:adidas - format:openapi - spec:paths - spec:request-body - spec:media-types - experience:consistency - experience:usability require-https-servers: description: "ALL requests MUST go through `https` protocol only. It requires the targeted value to match the pattern `/^https:/` (evaluated at `$.servers..url`). Severity: error." 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:/ tags: - source:adidas - format:openapi - spec:servers - experience:security success-response-use-hal-json: description: 'All success responses MUST be of media type `application/hal+json`. It requires the targeted value to be one of ["application/hal+json"] (evaluated at `$.paths..responses[?( @property >= 201 && @property < 300 && @property != 204)].content[*]~`). Severity: error.' 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 tags: - source:adidas - format:openapi - spec:paths - spec:responses - spec:media-types - experience:consistency - experience:data-modeling ok-response-use-hal-or-problem-json: description: 'All success responses MUST be of media type `application/hal+json` or `application/problem+json`. It requires the targeted value to be one of ["application/hal+json","application/problem+json"] (evaluated at `$.paths..responses[?( @property == 200 )].content[*]~`). Severity: error.' 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 tags: - source:adidas - format:openapi - spec:paths - spec:responses - spec:media-types - experience:consistency - experience:data-modeling success-response-match-hal-schema: description: 'All success responses MUST follow `application/hal+json` schema. It validates the `schema` field against a JSON Schema (evaluated at `$.paths..responses[?( @property == 200 && @property < 300 && @property != 204)].content[?(@property === "application/hal+json")]`). Severity: error.' 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 tags: - source:adidas - format:openapi - spec:paths - spec:responses - spec:media-types - experience:data-modeling - experience:consistency get-no-request-body: description: "GET requests MUST NOT have a request body. It requires the targeted value to be absent or empty (evaluated at `$.paths[*].get.requestBody`). Severity: error." severity: error recommended: true formats: - oas3 given: $.paths[*].get.requestBody then: function: falsy message: "{{description}}: {{error}}" tags: - source:adidas - format:openapi - spec:paths - spec:operations - spec:request-body - experience:consistency - experience:usability post-not-for-retrieval: description: "POST requests SHOULD NOT be used for retrieving information. Use GET instead. It requires the `summary` field not to match `(retrieve|fetch|get|read)` (evaluated at `$.paths[*].post`). Severity: error." severity: error recommended: true formats: - oas3 given: $.paths[*].post then: field: summary function: pattern functionOptions: notMatch: (retrieve|fetch|get|read) message: "{{description}}: {{error}}" tags: - source:adidas - format:openapi - spec:paths - spec:operations - experience:consistency - experience:usability put-require-request-body: description: "PUT requests MUST have a request body. It requires the `requestBody` field to be present and non-empty (evaluated at `$.paths[*].put`). Severity: error." severity: error recommended: true formats: - oas3 given: $.paths[*].put then: field: requestBody function: truthy message: "{{description}}: {{error}}" tags: - source:adidas - format:openapi - spec:paths - spec:operations - experience:consistency - experience:usability delete-no-request-body: description: "DELETE requests MUST NOT have a request body. It requires the targeted value to be absent or empty (evaluated at `$.paths[*].delete.requestBody`). Severity: error." severity: error recommended: true formats: - oas3 given: $.paths[*].delete.requestBody then: function: falsy message: "{{description}}: {{error}}" tags: - source:adidas - format:openapi - spec:paths - spec:operations - spec:request-body - experience:consistency - experience:usability paths-no-verbs: description: "API paths MUST be resource-focused and MUST NOT include verbs like 'get', 'update', 'create', or 'delete'. It requires the targeted value not to match `/\\b(get|update|create|delete|fetch|retrieve)\\b/` (evaluated at `$.paths[*]~`). Severity: warn." severity: warn recommended: true formats: - 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/ tags: - source:adidas - format:openapi - spec:paths - experience:naming - experience:consistency require-realistic-examples: description: "API design SHOULD include real-like examples for request and response definitions. It requires the `example` field to be present and non-empty (evaluated at `$..[?(@.example || @.examples)]`). Severity: warn." severity: warn recommended: true formats: - 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 tags: - source:adidas - format:openapi - spec:examples - experience:documentation - experience:usability version-semantic-and-stable: 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. It requires the targeted value to match the pattern `^(?!.*\\b(SNAPSHOT|RELEASE)\\b)(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\ \\d*)$` (evaluated at `$.info.version`). Severity: error." severity: error recommended: true formats: - 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*)$ tags: - source:adidas - format:openapi - spec:info - experience:versioning - experience:consistency require-root-security: description: "The API contract MUST include a 'security' section at the root level. It requires the `security` field to be present and non-empty (evaluated at `$`). Severity: error." severity: error recommended: true formats: - oas3 message: "{{description}}: {{error}}" given: $ then: field: security function: truthy tags: - source:adidas - format:openapi - spec:document - experience:security - experience:governance require-components-section: description: "The API contract MUST include a 'components' section. It requires the `components` field to be present and non-empty (evaluated at `$`). Severity: error." severity: error recommended: true formats: - oas3 message: "{{description}}: {{error}}" given: $ then: field: components function: truthy tags: - source:adidas - format:openapi - spec:document - experience:consistency - experience:governance require-security-schemes: description: "The API contract MUST include a 'securitySchemes' subsection under the 'components' section. It requires the `securitySchemes` field to be present and non-empty (evaluated at `$.components`). Severity: error." severity: error recommended: true formats: - oas3 message: "{{description}}: {{error}}" given: $.components then: field: securitySchemes function: truthy tags: - source:adidas - format:openapi - spec:components - experience:security - experience:governance - source:api-evangelist info-require-leanix-id: description: "The API contract SHOULD include a custom field 'x-leanixid' in the 'info' section. It requires the `x-leanixid` field to be present and non-empty (evaluated at `$.info`). Severity: warn." severity: warn recommended: true formats: - oas3 message: "{{description}}: {{error}}" given: $.info then: field: x-leanixid function: truthy tags: - source:adidas - format:openapi - spec:info - experience:governance - experience:discoverability leanix-id-valid-uuid: description: "The API contract SHOULD include a custom field 'x-leanixid' containing a valid UUID. It requires the targeted value to match the pattern `^[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}$` (evaluated at `$.info.x-leanixid`). Severity: warn." severity: warn recommended: true formats: - 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}$ tags: - source:adidas - format:openapi - spec:info - experience:governance - experience:consistency info-require-gateway: description: "The API contract SHOULD include a custom field 'x-gateway' in the 'info' section. It requires the `x-gateway` field to be present and non-empty (evaluated at `$.info`). Severity: warn." severity: warn recommended: true formats: - oas3 message: "{{description}}: {{error}}" given: $.info then: field: x-gateway function: truthy tags: - source:adidas - format:openapi - spec:info - experience:governance gateway-from-allowed-list: description: "The 'x-gateway' property, if present, MUST have a value in the enumeration: kong, nginx, aws, akamai, sap, other. It requires the `x-gateway` field to be one of [\"kong\",\"nginx\",\"aws\",\"akamai\",\"sap\",\"other\"] (evaluated at `$`). Severity: warn." severity: warn recommended: true formats: - oas3 given: $ then: field: x-gateway function: enumeration functionOptions: values: - kong - nginx - aws - akamai - sap - other tags: - source:adidas - format:openapi - spec:document - experience:governance - experience:consistency responses-include-hypermedia-links: description: "The API contract MAY include hypermedia links to represent the state of resources and be navigable. It requires the `links` field to be present and non-empty (evaluated at `$.paths[*][*].responses[*]`). Severity: hint." severity: hint recommended: true formats: - oas3 message: "{{description}}: {{error}}" given: $.paths[*][*].responses[*] then: field: links function: truthy tags: - source:adidas - format:openapi - spec:paths - spec:responses - experience:discoverability - experience:usability uri-versioning-single-version: message: Path can contain correct URI versioning description: "CAN use correct URI versioning [115a]. It requires the targeted value to match the pattern `^((?!.*\\/v\\d+(\\/.*)?\\/v\\d+)\\/.*)$` (evaluated at `$.paths.*~`). Severity: error." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/can-use-correct-URI-versioning.test.md severity: error given: $.paths.*~ then: function: pattern functionOptions: match: ^((?!.*\/v\d+(\/.*)?\/v\d+)\/.*)$ tags: - source:baloise - format:openapi - spec:paths - experience:versioning - experience:consistency property-names-camel-case: message: Property name has to be ASCII camelCase description: "MUST property names must be ASCII camelCase [118a]. It requires the targeted value to match the pattern `^[a-z]+((\\d)|([A-Z0-9][a-z0-9]+))*([A-Z])?$` (evaluated at `$.paths.*.*[responses,requestBody]..content..schema..properties.*~`). Severity: error." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/property-names-must-be-ascii-camel-case.md severity: error given: $.paths.*.*[responses,requestBody]..content..schema..properties.*~ then: function: pattern functionOptions: match: ^[a-z]+((\d)|([A-Z0-9][a-z0-9]+))*([A-Z])?$ tags: - source:baloise - format:openapi - spec:paths - spec:request-body - spec:responses - spec:media-types - spec:schemas - experience:naming - experience:consistency use-standard-status-codes: message: "{{property}} is not a standardized response code" description: 'MUST use standard HTTP status codes [150a]. It requires the targeted value to be one of ["100","101","200","201","202","203","204","205","206","207","300","301","302","303","304","305","307","400","401","402","403","404","405","406","407","408","409","410","411","412","413","414","415","416","417","422","423","426","428","429","431","500","501","502","503","504","505","511","default"] (evaluated at `$.paths.*.*.responses.*~`). Severity: error.' documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/must-use-additional-standard-http-status-codes.md severity: error given: $.paths.*.*.responses.*~ then: function: enumeration functionOptions: values: - "100" - "101" - "200" - "201" - "202" - "203" - "204" - "205" - "206" - "207" - "300" - "301" - "302" - "303" - "304" - "305" - "307" - "400" - "401" - "402" - "403" - "404" - "405" - "406" - "407" - "408" - "409" - "410" - "411" - "412" - "413" - "414" - "415" - "416" - "417" - "422" - "423" - "426" - "428" - "429" - "431" - "500" - "501" - "502" - "503" - "504" - "505" - "511" - default tags: - source:baloise - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:consistency prefer-400-over-422: message: Prefer 400 over 422 as response code description: "MUST use standard HTTP status codes [150a]. It requires the `422` field to be defined (evaluated at `$.paths.*.*.responses.422`). Severity: warn." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/must-use-additional-standard-http-status-codes.md severity: warn given: $.paths.*.*.responses.422 then: field: "422" function: defined tags: - source:baloise - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:consistency operation-well-understood-status-codes: message: "{{error}}" description: "MUST use standard HTTP status codes [150]. It applies a custom validation to the targeted value (evaluated at `$.paths.*`). Severity: warn." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/should-use-additional-well-understood-http-status-codes.md severity: warn given: $.paths.* then: function: baloise:assert-http-codes-for-operation functionOptions: wellUnderstood: "200": - ALL "201": - POST - PUT "202": - POST - PUT - DELETE - PATCH "204": - PUT - DELETE - PATCH "207": - POST "301": - ALL "303": - PATCH - POST - PUT - DELETE "304": - GET - HEAD "400": - ALL "401": - ALL "403": - ALL "404": - ALL "405": - ALL "406": - ALL "408": - ALL "409": - POST - PUT - DELETE - PATCH "410": - ALL "412": - PUT - DELETE - PATCH "415": - POST - PUT - DELETE - PATCH "422": - ALL "423": - PUT - DELETE - PATCH "428": - ALL "429": - ALL "500": - ALL "501": - ALL "503": - ALL default: - ALL tags: - source:baloise - format:openapi - spec:paths - experience:error-handling - experience:consistency require-tracing-headers: message: Header X-B3-Traceid, X-B3-Spanid or traceparent (w3c) missing description: "MUST use b3 or w3c tracing [233a]. It applies a custom validation to the targeted value (evaluated at `$.paths.*`). Severity: error." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/requests-must-use-tracing.md severity: error given: $.paths.* then: function: baloise:validate-tracing tags: - source:baloise - format:openapi - spec:paths - experience:reliability - experience:governance info-require-audience: message: Missing or wrong `info.x-audience`. description: "MUST provide API audience [219]. It requires the `x-audience` field to be present and non-empty, and requires the `x-audience` field to match the pattern `^(team-internal|domain-internal|company-internal|external-partner|extern\ al-public)$` (evaluated at `$.info`). Severity: error." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/property-names-must-be-ascii-camel-case.md severity: error given: $.info then: - field: x-audience function: truthy - field: x-audience function: pattern functionOptions: match: ^(team-internal|domain-internal|company-internal|external-partner|external-public)$ tags: - source:baloise - format:openapi - spec:info - experience:governance - experience:discoverability query-parameters-camel-case: message: Query parameter name has to be ASCII camelCase description: "MUST query parameter names must be ASCII camelCase [130a]. It requires the targeted value to match the pattern `^[a-z]+((\\d)|([A-Z0-9][a-z0-9]+))*([A-Z])?$` (evaluated at `$.paths.*.*.parameters[?(@ && @.in=='query')].name`). Severity: error." documentationUrl: https://github.com/baloise-incubator/spectral-ruleset/blob/main/doc/rules/query-parameter-names-must-be-ascii-camel-case.md severity: error given: $.paths.*.*.parameters[?(@ && @.in=='query')].name then: function: pattern functionOptions: match: ^[a-z]+((\d)|([A-Z0-9][a-z0-9]+))*([A-Z])?$ tags: - source:baloise - format:openapi - spec:paths - spec:parameters - experience:naming - experience:consistency responses-include-ratelimit-headers: description: "Response must include ratelimit-x headers. It requires the `headers.ratelimit-limit` field to be present and non-empty, and requires the `headers.ratelimit-remaining` field to be present and non-empty, and requires the `headers.ratelimit-reset` field to be present and non-empty (evaluated at `$..responses.*`). Severity: error." message: "{{description}}; missing {{property}}" severity: error given: $..responses.* then: - field: headers.ratelimit-limit function: truthy - field: headers.ratelimit-remaining function: truthy - field: headers.ratelimit-reset function: truthy tags: - source:digitalocean - format:openapi - spec:responses - experience:reliability - experience:documentation properties-require-examples: description: "Object properties must include examples. It applies a custom validation to the targeted value (evaluated at `$..properties..properties.*`). Severity: error." given: $..properties..properties.* severity: error message: "{{description}}; {{property}}" then: function: digitalocean:ensurePropertiesExample tags: - source:digitalocean - format:openapi - spec:schemas - experience:documentation - experience:usability parameters-require-examples: description: 'Parameters must include examples. It requires exactly one of ["example","examples"] to be present (evaluated at `$..parameters.*`). Severity: error.' given: $..parameters.* severity: error message: "{{description}}; missing {{property}}" then: function: xor functionOptions: properties: - example - examples tags: - source:digitalocean - format:openapi - spec:parameters - experience:documentation - experience:usability headers-require-examples: description: "Headers must include examples. It applies a custom validation to the targeted value (evaluated at `$..headers.*`). Severity: error." given: $..headers.* severity: error message: "{{description}}; missing {{property}}" then: function: digitalocean:ensurePropertiesExample tags: - source:digitalocean - format:openapi - spec:headers - experience:documentation - experience:usability operations-use-ref: description: "Endpoint must be a $ref. It requires the `$ref` field to be present and non-empty (evaluated at `$.paths.*.*`). Severity: error." message: "{{description}}; {{property}} incorrect" severity: error resolved: false given: $.paths.*.* then: field: $ref function: truthy tags: - source:digitalocean - format:openapi - spec:paths - experience:consistency - experience:governance paths-include-version: description: "Path must include the version. It requires the targeted value to match the pattern `^(/v[12]/.*|/api/v[12]/.*)$` (evaluated at `$.paths[?(@property!='/')]~`). Severity: error." message: "{{description}}; {{property}} incorrect" severity: error resolved: false given: $.paths[?(@property!='/')]~ then: function: pattern functionOptions: match: ^(/v[12]/.*|/api/v[12]/.*)$ tags: - source:digitalocean - format:openapi - spec:paths - experience:versioning - experience:consistency operation-ref-resource-file: description: "Endpoint must a $ref to a file in resources/. It requires the targeted value to match the pattern `^resources/.*yml$` (evaluated at `$.paths.*.$ref`). Severity: error." message: "{{description}}; {{value}} incorrect" severity: error resolved: false given: $.paths.*.$ref then: function: pattern functionOptions: match: ^resources/.*yml$ tags: - source:digitalocean - format:openapi - spec:paths - experience:consistency - experience:governance responses-define-401: description: "Responses should contain common response - 401 (unauthorized). It requires the `401` field to be present and non-empty (evaluated at `$.paths..responses`). Severity: error." message: "{{description}}. Missing {{property}}" severity: error given: $.paths..responses then: field: "401" function: truthy tags: - source:digitalocean - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:documentation responses-define-404: description: "Responses should contain common response - 404 (not found). It requires the `404` field to be present and non-empty (evaluated at `$.paths[?(@property.match(/.*\\/{.*}.*/))]..responses`). Severity: error." message: "{{description}}. Missing {{property}}" severity: error given: $.paths[?(@property.match(/.*\/{.*}.*/))]..responses then: field: "404" function: truthy tags: - source:digitalocean - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:documentation responses-define-429: description: "Responses should contain common response - 429 (too many requests). It requires the `429` field to be present and non-empty (evaluated at `$.paths..responses`). Severity: error." message: "{{description}}. Missing {{property}}" severity: error given: $.paths..responses then: field: "429" function: truthy tags: - source:digitalocean - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:reliability responses-define-500: description: "Responses should contain common response - 500 (server error). It requires the `500` field to be present and non-empty (evaluated at `$.paths..responses`). Severity: error." message: "{{description}}. Missing {{property}}" severity: error given: $.paths..responses then: field: "500" function: truthy tags: - source:digitalocean - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:reliability array-properties-typed-items: description: "Array properties must have an items attribute with a type. It applies a custom validation to the targeted value (evaluated at `$..*.properties[*]`). Severity: error." given: $..*.properties[*] severity: error message: "{{error}}" then: function: digitalocean:ensureAllArraysHaveItemTypes tags: - source:digitalocean - format:openapi - spec:schemas - experience:data-modeling - experience:consistency array-parameters-typed-items: description: "Array parameters must have an items attribute with a type. It applies a custom validation to the targeted value (evaluated at `$..*.parameters[*]`). Severity: error." given: $..*.parameters[*] severity: error message: "{{error}}" then: function: digitalocean:ensureAllArraysHaveItemTypes tags: - source:digitalocean - format:openapi - spec:parameters - experience:data-modeling - experience:consistency schema-keys-snake-case: description: "schema key must be snake cased (e.g. snake_case). It applies a custom validation to the targeted value (evaluated at `$.components['schemas'].*~`). Severity: error." type: style given: $.components['schemas'].*~ severity: error message: "{{error}}" then: function: digitalocean:ensureSnakeCaseWithDigits tags: - source:digitalocean - format:openapi - spec:schemas - spec:components - experience:naming - experience:consistency parameter-keys-snake-case: description: "parameter key must be snake cased (e.g. snake_case). It applies a custom validation to the targeted value (evaluated at `$.components['parameters'].*~`). Severity: error." type: style given: $.components['parameters'].*~ severity: error message: "{{error}}" then: function: digitalocean:ensureSnakeCaseWithDigits tags: - source:digitalocean - format:openapi - spec:parameters - spec:components - experience:naming - experience:consistency example-keys-snake-case: description: "example key must be snake cased (e.g. snake_case). It applies a custom validation to the targeted value (evaluated at `$.components['examples'].*~`). Severity: error." type: style given: $.components['examples'].*~ severity: error message: "{{error}}" then: function: digitalocean:ensureSnakeCaseWithDigits tags: - source:digitalocean - format:openapi - spec:components - spec:examples - experience:naming - experience:consistency response-keys-snake-case: description: "response key must be snake cased (e.g. snake_case). It applies a custom validation to the targeted value (evaluated at `$.components['responses'].*~`). Severity: error." type: style given: $.components['responses'].*~ severity: error message: "{{error}}" then: function: digitalocean:ensureSnakeCaseWithDigits tags: - source:digitalocean - format:openapi - spec:responses - spec:components - experience:naming - experience:consistency schema-properties-require-type: description: "Schema properties must have a type defined. It applies a custom validation to the targeted value (evaluated at `$..properties.*`). Severity: error." given: $..properties.* severity: error message: "{{error}}" then: function: digitalocean:ensureSchemaHasType tags: - source:digitalocean - format:openapi - spec:schemas - experience:data-modeling - experience:consistency operation-require-security: description: "Check operation security is defined. It requires the `security` field to be present and non-empty (evaluated at `$.paths.*.*`). Severity: error." severity: error given: $.paths.*.* then: field: security function: truthy tags: - source:digitalocean - format:openapi - spec:paths - experience:security - experience:governance operation-security-use-defined-scheme: description: "Check operation security uses a defined security scheme. It validates the targeted value against a JSON Schema (evaluated at `$.paths[*][*]..security.*`). Severity: error." severity: error given: $.paths[*][*]..security.* then: function: schema functionOptions: schema: anyOf: - required: - bearer_auth - required: - inference_bearer_auth tags: - source:digitalocean - format:openapi - spec:security - spec:paths - experience:security - experience:consistency info-microcks-extension-valid: description: "x-microcks extension must be valid. It validates the targeted value against a JSON Schema (evaluated at `$.info.x-microcks`). Severity: warn." message: x-microcks extension must be valid formats: - oas3 - aas2 - aas3 severity: warn given: $.info.x-microcks then: function: schema functionOptions: schema: type: object properties: labels: type: object additionalProperties: type: string required: - labels additionalProperties: false tags: - source:microcks - format:openapi - spec:info - experience:governance - experience:consistency operation-microcks-extension-valid: description: "x-microcks-operation extension must be valid. It validates the targeted value against a JSON Schema (evaluated at `$.paths.*.*.x-microcks-operation`, `$.channels.*.[publish,subscribe].x-microcks-operation`, `$.operations.*.x-microcks-operation`). Severity: warn." message: x-microcks-operation extension must be valid formats: - oas3 - aas2 - aas3 severity: warn given: - $.paths.*.*.x-microcks-operation - $.channels.*.[publish,subscribe].x-microcks-operation - $.operations.*.x-microcks-operation then: function: schema functionOptions: schema: type: object properties: delay: type: number format: int32 frequency: type: number format: int32 dispatcher: type: string dispatcherRules: type: string parameterConstraints: type: array items: type: object properties: name: type: string in: type: string enum: - path - query - header required: type: boolean recopy: type: boolean mustMatchRegexp: type: string required: - name - in additionalProperties: false tags: - source:microcks - format:openapi - spec:channels - spec:paths - experience:governance - experience:consistency required-parameters-require-examples: description: "Required param must have examples. It requires the `examples` field to be present and non-empty (evaluated at `$..parameters[?(@ && @.required == true)]`). Severity: warn." message: Required param must have examples formats: - oas3 severity: warn given: $..parameters[?(@ && @.required == true)] then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:parameters - experience:documentation - experience:usability optional-parameters-include-examples: description: "Optional param should have examples. It requires the `examples` field to be present and non-empty (evaluated at `$..parameters[?(@ && @.required != true)]`). Severity: info." message: Optional param should have examples formats: - oas3 severity: info given: $..parameters[?(@ && @.required != true)] then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:parameters - experience:documentation - experience:usability request-content-require-examples: description: "Request with content must have examples. It requires the `examples` field to be present and non-empty (evaluated at `$.paths..requestBody..content.*`). Severity: warn." message: Request with content must have examples formats: - oas3 severity: warn given: $.paths..requestBody..content.* then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:paths - spec:request-body - spec:media-types - experience:documentation - experience:usability response-content-require-examples: description: "Response with content must have examples. It requires the `examples` field to be present and non-empty (evaluated at `$.paths..responses..content.*`). Severity: warn." message: Response with content must have examples formats: - oas3 severity: warn given: $.paths..responses..content.* then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:paths - spec:responses - spec:media-types - experience:documentation - experience:usability examples-form-complete-mocks: description: "Response example must match required params examples to form full mocks. It applies a custom validation to the targeted value (evaluated at `$.paths.*.*`). Severity: warn." message: "{{error}}" formats: - oas3 severity: warn given: $.paths.*.* then: function: microcks:oas-verify-mocks tags: - source:microcks - format:openapi - spec:paths - experience:documentation - experience:usability messages-require-examples: description: "Message must have examples. It requires the `examples` field to be present and non-empty (evaluated at `$.channels.*.[publish,subscribe].message`). Severity: warn." message: Message must have examples formats: - aas2 severity: warn given: $.channels.*.[publish,subscribe].message then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:channels - spec:messages - experience:documentation - experience:usability component-messages-require-examples: description: "Message must have examples. It requires the `examples` field to be present and non-empty (evaluated at `$.components.messages.*`). Severity: warn." message: Message must have examples formats: - aas3 severity: warn given: $.components.messages.* then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:messages - spec:components - experience:documentation - experience:usability channel-parameters-require-examples: description: "Parameter must have examples. It requires the `examples` field to be present and non-empty (evaluated at `$.channels.*.parameters.*.schema`). Severity: warn." message: Parameter must have examples formats: - aas2 severity: warn given: $.channels.*.parameters.*.schema then: field: examples function: truthy tags: - source:microcks - format:openapi - spec:channels - spec:parameters - spec:schemas - experience:documentation - experience:usability message-examples-form-complete-mocks: description: "Message example must match params examples to form full mocks. It applies a custom validation to the targeted value (evaluated at `$.channels.*`). Severity: warn." message: "{{error}}" formats: - aas2 severity: warn given: $.channels.* then: function: microcks:aas-verify-mocks tags: - source:microcks - format:openapi - spec:channels - experience:documentation - experience:usability info-require-description: description: "Info section is missing a description. It requires the `description` field to be present and non-empty (evaluated at `$.info`). Severity: error." formats: - oas3 - oas3_1 given: $.info recommended: true resolved: true severity: error then: field: description function: truthy type: validation tags: - source:paystack - format:openapi - spec:info - experience:documentation - source:api-evangelist operation-id-url-safe: description: "OperationId must use URL friendly characters. It requires the `operationId` field to match the pattern `^[A-Za-z0-9-._~:/?#\\[\\]@!\\$&'()*+,;=]*$` (evaluated at `$.paths[*][*]`). Severity: error." formats: - oas3 - oas3_1 given: $.paths[*][*] recommended: true resolved: true severity: error then: field: operationId function: pattern functionOptions: match: ^[A-Za-z0-9-._~:/?#\[\]@!\$&'()*+,;=]*$ type: validation tags: - source:paystack - format:openapi - spec:paths - experience:naming - experience:consistency path-parameters-not-empty: description: "Path parameter declarations must not be empty ex. `/api/{}` is invalid. It requires the targeted value not to match `{}` (evaluated at `$.paths`). Severity: error." formats: - oas3 - oas3_1 given: $.paths recommended: true resolved: true severity: error then: function: pattern functionOptions: notMatch: "{}" type: validation tags: - source:paystack - format:openapi - spec:paths - experience:consistency - experience:usability paths-no-trailing-slash: description: "Path must not end with a slash. It requires the targeted value not to match `.+\\/$` (evaluated at `$.paths`). Severity: warn." formats: - oas3 - oas3_1 given: $.paths recommended: true resolved: true severity: warn then: function: pattern functionOptions: notMatch: .+\/$ type: validation tags: - source:paystack - format:openapi - spec:paths - experience:naming - experience:consistency paths-no-query-string: description: "Path must not include query string. It requires the targeted value not to match `\\?` (evaluated at `$.paths`). Severity: error." formats: - oas3 - oas3_1 given: $.paths recommended: true resolved: true severity: error then: function: pattern functionOptions: notMatch: \? type: validation tags: - source:paystack - format:openapi - spec:paths - experience:naming - experience:consistency document-cache-control-parameter: description: 'Cache usage SHOULD be extensively detailed in the `description` property to avoid data leaks or the usage of stale data. This rule should ensure in some way that the api provider documented extensively the cache usage to avoid data leaks or usage of stale data. For now this ruleset tests: * the presence of following keywords in the `description`: `max-age`, `private`, `no-store`, `no-cache`. * that one and only one between Expires and Cache-Control is used. `Cache-Control` and `Expires` should not be used in conjuction, because `Cache-Control` overrides `Expires` when `max-age` is set. Instead if neither `Cache-Control` or `Expires` are set, clients MAY use euristic cache like described in RFC7234. It requires the `description` field to be present and non-empty, and requires the `description` field to match the pattern `.*(max-age|private|no-store|no-cache).*` (evaluated at `$..[parameters][?(@.in == "header" && @.name.match(/Cache-Control/i))]`). Severity: warn.' message: Cache usage SHOULD be documented when used. formats: - oas3 severity: warn recommended: true given: $..[parameters][?(@.in == "header" && @.name.match(/Cache-Control/i))] then: - field: description function: truthy - field: description function: pattern functionOptions: match: .*(max-age|private|no-store|no-cache).* tags: - source:team-digitale - format:openapi - spec:parameters - spec:headers - experience:documentation - experience:reliability document-cache-response-headers: description: 'Cache usage SHOULD be extensively detailed in the `description` property to avoid data leaks or the usage of stale data. This rule should ensure in some way that the api provider documented extensively the cache usage to avoid data leaks or usage of stale data. For now this ruleset tests: * the presence of following keywords in the `description`: `max-age`, `private`, `no-store`, `no-cache`. * that one and only one between Expires and Cache-Control is used. `Cache-Control` and `Expires` should not be used in conjuction, because `Cache-Control` overrides `Expires` when `max-age` is set. Instead if neither `Cache-Control` or `Expires` are set, clients MAY use euristic cache like described in RFC7234. It requires the `description` field to be present and non-empty, and requires the `description` field to match the pattern `.*(max-age|private|no-store|no-cache).*` (evaluated at `$.[responses][?(@property[0] == "2" )][headers].[?(@property.match(/Cache-Control|Expires/i))]]`). Severity: info.' message: Cache usage in responses SHOULD be documented in Cache-Control and/or Expires. {{error}} formats: - oas3 severity: info recommended: true given: $.[responses][?(@property[0] == "2" )][headers].[?(@property.match(/Cache-Control|Expires/i))]] then: - field: description function: truthy - field: description function: pattern functionOptions: match: .*(max-age|private|no-store|no-cache).* tags: - source:team-digitale - format:openapi - spec:responses - spec:headers - experience:documentation - experience:reliability cache-headers-no-conflict: description: 'Cache usage SHOULD be extensively detailed in the `description` property to avoid data leaks or the usage of stale data. This rule should ensure in some way that the api provider documented extensively the cache usage to avoid data leaks or usage of stale data. For now this ruleset tests: * the presence of following keywords in the `description`: `max-age`, `private`, `no-store`, `no-cache`. * that one and only one between Expires and Cache-Control is used. `Cache-Control` and `Expires` should not be used in conjuction, because `Cache-Control` overrides `Expires` when `max-age` is set. Instead if neither `Cache-Control` or `Expires` are set, clients MAY use euristic cache like described in RFC7234. It requires exactly one of ["Expires","Cache-Control"] to be present (evaluated at `$.[responses][?(@property[0] == "2" )][headers]`). Severity: info.' message: "{{error}}" formats: - oas3 severity: info recommended: true given: $.[responses][?(@property[0] == "2" )][headers] then: - function: xor functionOptions: properties: - Expires - Cache-Control tags: - source:team-digitale - format:openapi - spec:responses - spec:headers - experience:reliability - experience:consistency path-segments-kebab-case-2: x-tags: - it description: "Paths should be kebab-case. See Italian recommendation RAC_REST_NAME_002. It requires the targeted value to match the pattern `^(/[a-z0-9-.]+|/{[a-zA-Z0-9_]+})+$` (evaluated at `$.paths[*]~`). Severity: warn." message: "{{property}} is not kebab-case: {{error}}" severity: warn recommended: true given: $.paths[*]~ then: function: pattern functionOptions: match: ^(/[a-z0-9-.]+|/{[a-zA-Z0-9_]+})+$ tags: - source:team-digitale - format:openapi - spec:paths - experience:naming - experience:consistency request-header-names-pascal-case: x-tags: - it description: 'Headers should be pascal-case. See Italian recommendation RAC_REST_NAME_003. It requires pascal casing on the targeted value (evaluated at `$.[parameters][?(@.in=="header")].name`). Severity: hint.' message: "{{value}} {{error}} in {{path}}" severity: hint recommended: true given: - $.[parameters][?(@.in=="header")].name then: function: casing functionOptions: type: pascal separator: char: "-" tags: - source:team-digitale - format:openapi - spec:parameters - spec:headers - experience:naming - experience:consistency response-header-names-pascal-case: x-tags: - it description: "Headers should be pascal-case. See Italian recommendation RAC_REST_NAME_003. It requires pascal casing on the targeted value (evaluated at `$.[responses][*].headers.*~`). Severity: hint." message: "Header {{error}}: {{path}}" severity: hint recommended: true given: - $.[responses][*].headers.*~ then: function: casing functionOptions: type: pascal separator: char: "-" tags: - source:team-digitale - format:openapi - spec:responses - spec:headers - experience:naming - experience:consistency no-forbidden-http-headers: x-tags: - standards description: "OAS do not allow using the following HTTP headers in a specification file: Authorization, Content-Type and Accept. You MUST use the associate functionalities provided by OAS, instead. It requires the targeted value not to match `/^(accept|content-type|authorization)$/i` (evaluated at `$..parameters[?(@.in == 'header')].name`, `$.[responses][*].headers.*~`). Severity: error." message: "{{error}} in {{path}} {{value}}" severity: error given: - $..parameters[?(@.in == 'header')].name - $.[responses][*].headers.*~ then: function: pattern functionOptions: notMatch: /^(accept|content-type|authorization)$/i tags: - source:team-digitale - format:openapi - spec:parameters - spec:responses - spec:headers - experience:consistency - experience:governance headers-no-x-prefix: x-tags: - standards description: "'HTTP' headers SHOULD NOT start with 'X-' RFC6648. It requires the targeted value to match the pattern `/^([^x]|.[^-])|RateLimit-/i` (evaluated at `$..parameters[?(@.in == 'header')].name`). Severity: warn." severity: warn given: - $..parameters[?(@.in == 'header')].name message: HTTP header '{{value}}' SHOULD NOT start with 'X-' in {{path}} recommended: true type: style then: function: pattern functionOptions: match: /^([^x]|.[^-])|RateLimit-/i tags: - source:team-digitale - format:openapi - spec:parameters - spec:headers - experience:naming - experience:consistency response-headers-no-x-prefix: x-tags: - standards description: "'HTTP' headers SHOULD NOT start with 'X-' RFC6648. It requires the targeted value to match the pattern `/^([^x]|.[^-])|RateLimit-/i` (evaluated at `$.[responses][*].headers.*~`). Severity: warn." severity: warn given: - $.[responses][*].headers.*~ message: HTTP response header SHOULD NOT start with 'X-' in {{path}} recommended: true type: style then: function: pattern functionOptions: match: /^([^x]|.[^-])|RateLimit-/i tags: - source:team-digitale - format:openapi - spec:responses - spec:headers - experience:naming - experience:consistency server-require-description: x-tags: - metadata - it description: "Servers must have a description. It requires the `description` field to be present and non-empty (evaluated at `$.servers[*]`, `$.paths..servers`). Severity: error." message: Server {{path}} must have a description. given: - $.servers[*] - $.paths..servers severity: error recommended: true then: field: description function: truthy tags: - source:team-digitale - format:openapi - spec:servers - spec:paths - experience:documentation require-https-servers-2: x-tags: - security description: 'Servers must use https to ensure the origin of the responses and protect the integrity and the confidentiality of the communication. You can use `http://` only on sandboxes environment. Use `x-sandbox: true` to skip this kind of check. It requires the `url` field to match the pattern `^https://.*` (evaluated at `$.servers[?(@["x-sandbox"] != true)]`, `$.paths..servers[?(@["x-sandbox"] != true)]`). Severity: error.' message: "Non-sandbox url {{value}} {{error}}. Add `x-sandbox: true` to skip this check on a specific server." given: - $.servers[?(@["x-sandbox"] != true)] - $.paths..servers[?(@["x-sandbox"] != true)] severity: error recommended: true then: field: url function: pattern functionOptions: match: ^https://.* tags: - source:team-digitale - format:openapi - spec:servers - spec:paths - experience:security info-require-summary: x-tags: - it - metadata message: "API MUST have an one-liner #/info/x-summary field containing a brief description." description: "The `#/info/x-summary` can be used to specify a brief, one-liner description of your API: this is very useful for catalog purposes (eg. this can be shown as your API subtitle in catalogs and developer portals). In OAS3.1 you can use the standard `#/info/summary` field. It requires the `info.x-summary` field to be present and non-empty (evaluated at `$`). Severity: error." given: $ severity: error recommended: true type: style formats: - oas3 then: field: info.x-summary function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:documentation - experience:discoverability info-require-terms-of-service: x-tags: - metadata message: "API MUST reference the URL of the Terms of Service in #/info/termsOfService." description: "API MUST reference the URL of the Terms of Service in `#/info/termsOfService`. It requires the `info.termsOfService` field to be present and non-empty (evaluated at `$`). Severity: error." given: $ severity: error recommended: true type: style formats: - oas3 then: field: info.termsOfService function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:documentation - experience:governance info-require-contact: x-tags: - metadata description: "API MUST reference a contact, either url or email in #/info/contact. It requires the `info.contact` field to be present and non-empty (evaluated at `$`). Severity: error." given: $ severity: error recommended: true type: style formats: - oas3 then: field: info.contact function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:documentation - experience:discoverability info-require-api-identifier: x-tags: - it - metadata message: "API must have an unique identifier in x-api-id in #/info/x-api-id." description: "The `#/info/x-api-id` field can be used to associate an identifier to an API. This is useful to track an API even when its `#/info/title` changes. It requires the `info.x-api-id` field to be present and non-empty (evaluated at `$`). Severity: error." given: $ severity: error recommended: true type: style then: field: info.x-api-id function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:discoverability - experience:governance version-must-be-semver: description: "The API version field should follow [semantic versioning](https://semver.org/#semantic-versioning-specification-semver). It requires the targeted value to match the pattern `^[0-9]+.[0-9]+.[0-9]+(-[a-z0-9+.-]+)?` (evaluated at `$.info.version`). Severity: error." severity: error recommended: true message: Specs should follow semantic versioning. {{value}} is not a valid version. given: $.info.version then: function: pattern functionOptions: match: ^[0-9]+.[0-9]+.[0-9]+(-[a-z0-9+.-]+)? tags: - source:team-digitale - format:openapi - spec:info - experience:versioning - experience:consistency number-require-format: x-tags: - it - RAC_REST_FORMAT_004 description: 'Schema of type number or integer must specify a format to express the associated datatype, eg. `int32`, `int64`, ... You can express similar requirements using the `minimum` and `maximum` properties. See recommendation RAC_REST_FORMAT_004. It requires the `format` field to be present and non-empty (evaluated at `$.[?(@.type=="number")]`). Severity: error.' message: Schema of type number or integer must specify a format. {{path}} formats: - oas3 severity: error recommended: true given: $.[?(@.type=="number")] then: field: format function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:data-modeling - experience:consistency integer-require-format: x-tags: - it - RAC_REST_FORMAT_004 description: >- Schema of type number or integer must specify a format to express the associated datatype, eg. `int32`, `int64`, ... You can express similar requirements using the `minimum` and `maximum` properties. See recommendation RAC_REST_FORMAT_004. It requires the `format` field to be present and non-empty (evaluated at `$.[?(@.type=="integer")] `). Severity: error. message: Schema of type number or integer must specify a format. {{path}} formats: - oas3 severity: error recommended: true given: | $.[?(@.type=="integer")] then: field: format function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:data-modeling - experience:consistency integer-format-allowed-values: x-tags: - it - RAC_REST_FORMAT_004 description: >- To improve interoperability, integer and number formats are constrained to a shared subset. See recommendation RAC_REST_FORMAT_004. It requires the `format` field to be one of ["int32","int64"] (evaluated at `$.[?(@.type=="integer")] `). Severity: hint. message: Type format is "{{value}}", expected one of [int32, int64]. {{path}} formats: - oas3 severity: hint recommended: true given: | $.[?(@.type=="integer")] then: field: format function: enumeration functionOptions: values: - int32 - int64 tags: - source:team-digitale - format:openapi - spec:document - experience:data-modeling - experience:consistency number-format-allowed-values: x-tags: - it - RAC_REST_FORMAT_004 description: >- To improve interoperability, integer and number formats are constrained to a shared subset. See recommendation RAC_REST_FORMAT_004. It requires the `format` field to be one of ["decimal32","decimal64","float","double","decimal128"] (evaluated at `$.[?(@.type=="number")] `). Severity: hint. message: Type format is "{{value}}", expected one of [decimal32, decimal64, decimal128, float, double]. {{path}} formats: - oas3 severity: hint recommended: true given: | $.[?(@.type=="number")] then: field: format function: enumeration functionOptions: values: - decimal32 - decimal64 - float - double - decimal128 tags: - source:team-digitale - format:openapi - spec:document - experience:data-modeling - experience:consistency patch-media-type-not-plain-json: x-tags: - standards description: 'The PATCH specification explicits that the request body contains a "patch document" describing the changes to be applied to the target resource. To avoid confusion, [this errata](https://www.rfc-editor.org/errata/eid3169) explains that `application/json` is not an appropriate media-type for `PATCH`. A correct example of PATCH using eg. `application/json-patch+json` media-type defined in RFC6902. ``` paths: /books/{book_id}: patch: requestBody: content: application/json-patch+json: schema: type: object example: [{ "op": "add", "path": "/baz", "value": "qux" }] ```. It requires the `application/json` field to be absent or empty (evaluated at `$.[patch][requestBody][content]`). Severity: error.' message: application/json is not an appropriate media-type for PATCH. {{path}} formats: - oas3 severity: error recommended: true given: $.[patch][requestBody][content] then: field: application/json function: falsy tags: - source:team-digitale - format:openapi - spec:operations - spec:request-body - spec:media-types - experience:consistency - experience:data-modeling require-status-health-check-path: x-tags: - it description: "You must define a `/status` path that can be used to health-check the API. Using this path avoids the arbitrary usage of a server URL for health-check scope. The `/status` endpoint should return a `application/problem+json` response containing a successful status code if the service is working correctly. The service provider is free to define the implementation logic for this path. It requires the `paths./status.get.responses.200` field to be present and non-empty (evaluated at `$`). Severity: error." message: The "/status" path used to health-check the API must be defined. {{error}} severity: error recommended: true given: $ then: field: paths./status.get.responses.200 function: truthy tags: - source:team-digitale - format:openapi - spec:document - experience:reliability - experience:discoverability status-path-return-problem-type: x-tags: - it description: "\"/status\" must return a Problem object. It requires the targeted value to be one of [\"application/problem+xml\",\"application/problem+json\"] (evaluated at `$.paths.'/status'.get.responses.200.content.*~`). Severity: error." message: "{{error}}" severity: error recommended: true given: $.paths.'/status'.get.responses.200.content.*~ then: function: enumeration functionOptions: values: - application/problem+xml - application/problem+json tags: - source:team-digitale - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - experience:error-handling - experience:reliability status-path-problem-schema-fields: x-tags: - it description: "\"/status\" schema is not a Problem object. It requires the `properties.status` field to be present and non-empty, and requires the `properties.title` field to be present and non-empty, and requires the `properties.detail` field to be present and non-empty (evaluated at `$.paths.'/status'.get.responses.200.content.[[schema]]`). Severity: warn." message: "{{error}} {{path}}" severity: warn recommended: true given: $.paths.'/status'.get.responses.200.content.[[schema]] then: - function: truthy field: properties.status - function: truthy field: properties.title - function: truthy field: properties.detail tags: - source:team-digitale - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - spec:schemas - experience:error-handling - experience:reliability path-no-http-method-names: x-tags: - it description: "When you design a REST API, you don't usually need to mention terms like `get`, `delete` and so on in your `paths`, because this information is conveyed by the HTTP method. Instead of using ``` POST /books/1234/delete HTTP/1.1 Host: api.example ``` You can simply call ``` DELETE /books/1234 HTTP/1.1 Host: api.example ``` Similarly you don't need verbs like `list` or `create` because the HTTP Semantics RFC7231 supports this kind of actions natively with proper methods and status code. Instead of ``` POST /create/user HTTP/1.1 Host: api.example Content-Type: application/json {\"given_name\": \"Mario\"} ``` You can use ``` POST /create/user HTTP/1.1 Host: api.example Content-Type: application/json {\"given_name\": \"Mario\"} ``` returning a proper response ``` HTTP/1.1 201 Created Location: /users/1234 ``` This simplifies securing your API as you know beforehand the kind of action which is going to be performed. It requires the `@key` field to be undefined (evaluated at `$.paths[?(@property.match( /\\/(get|post|put|delete|patch)[\\/A-Z_\\-]?/ ))]~`, `$.paths[?(@property.match( /\\/(create|remove|list)[\\/A-Z_\\-]?/ ))]~`). Severity: hint." message: API "path" contains a name of an http method. {{error}} severity: hint recommended: true given: - $.paths[?(@property.match( /\/(get|post|put|delete|patch)[\/A-Z_\-]?/ ))]~ - $.paths[?(@property.match( /\/(create|remove|list)[\/A-Z_\-]?/ ))]~ then: field: "@key" function: undefined tags: - source:team-digitale - format:openapi - spec:paths - spec:operations - experience:naming - experience:consistency error-response-use-problem-type: description: 'Error management is a key enabler of a resilient API ecosystem. Enforcing a consistent schema for errors between different APIs, enables client to properly implement an error management strategy, with positive impacts for users. Error responses should return one of the media-type defined in RFC 9457: - `application/problem+json` - `application/problem+xml` An example of a valid response: ``` responses: "503": content: application/problem+json: schema: ... ```. It requires the targeted value to be one of ["application/problem+xml","application/problem+json"] (evaluated at `$.paths.[*].responses[?(@property.match(/^(4|5|default)/))].content.*~`). Severity: error.' message: Error responses should support RFC 9457 in {{path}}. formats: - oas3 severity: error given: $.paths.[*].responses[?(@property.match(/^(4|5|default)/))].content.*~ then: function: enumeration functionOptions: values: - application/problem+xml - application/problem+json tags: - source:team-digitale - format:openapi - spec:paths - spec:responses - spec:media-types - experience:error-handling - experience:consistency error-response-match-problem-schema: description: 'WARN: This rule is under implementation and just provides an hint. Error management is a key enabler of a resilient API ecosystem. Enforcing a consistent schema for errors between different APIs, enables client to properly implement an error management strategy, with positive impacts for users. This rule inspects the schema returned by an error response and verifies whether it contains the main properties defined in RFC 9457: `status`, `title` and `detail`. An example of a valid payload is ``` { "title": "Not Found", "status": 404, "detail": "Book does not exist; id: 123" } ``` See recommendation RAC_REST_NAME_007. It validates the targeted value against a JSON Schema (evaluated at `$.paths.[*].responses[?(@property.match(/^(4|5|default)/))][[schema]]`). Severity: hint.' message: Your schema doesn't seem to match RFC 9457. Are you sure it is ok? {{path}} formats: - oas3 severity: hint recommended: false given: $.paths.[*].responses[?(@property.match(/^(4|5|default)/))][[schema]] then: function: schema functionOptions: schema: type: object properties: status: type: integer title: type: string detail: type: string tags: - source:team-digitale - format:openapi - spec:paths - spec:responses - spec:schemas - experience:error-handling - experience:consistency error-schema-problem-property-names: description: 'WARN: This rule is under implementation and just provides an hint. Error management is a key enabler of a resilient API ecosystem. Enforcing a consistent schema for errors between different APIs, enables client to properly implement an error management strategy, with positive impacts for users. Errors should return RFC 9457 objects. Instead, this schema seems to use non standard properties such as: `message`, `msg` and `code`. An error of the following form ``` { "msg": "Book with id: 123 does not exist.", "code": 6063 } ``` can be expressed in RFC 9457 with ``` { "detail": "Book with id: 123 does not exist.", "type": "https://api.example/v1/errors/6063", "status": 404, "title": "Not Found" } ``` Returning an URI in `type`, instead of an opaque `code` can help the client in better identifying the error; moreover the URI though it should not be dereferenced automatically, can return an actual resource providing guidance in addressing the issue. See recommendation RAC_REST_NAME_007. It requires the `@key` field not to match `message|code|msg` (evaluated at `$.[responses][?(@property.match(/^(4|5|default)/))][[schema]][properties].*~`). Severity: hint.' message: Error response doesn't seem to match RFC 9457. Are you sure it is ok? {{path}} formats: - oas3 severity: hint recommended: true given: $.[responses][?(@property.match(/^(4|5|default)/))][[schema]][properties].*~ then: field: "@key" function: pattern functionOptions: notMatch: message|code|msg tags: - source:team-digitale - format:openapi - spec:responses - spec:schemas - experience:error-handling - experience:consistency throttled-response-require-retry-after: description: 'When a client is either: * throttled out with a 429 status code; * warned about a temporary server issue with a 503 status code; the server should explicitly communicate how long to wait before issuing further requests using the Retry-After header. Retry-After is defined in RFC7231. It requires the `Retry-After` field to be present and non-empty (evaluated at `$.[responses][?(@property == "429" || @property == "503" )][headers]`). Severity: warn.' message: "Missing ratelimit header: {{property}} in {{path}}" formats: - oas3 severity: warn recommended: true given: $.[responses][?(@property == "429" || @property == "503" )][headers] then: field: Retry-After function: truthy tags: - source:team-digitale - format:openapi - spec:responses - spec:headers - experience:reliability - experience:error-handling success-response-require-ratelimit-headers: x-tags: - it description: 'Ratelimiting API preserves a service and limits attack scenario [see API4:2019 Lack of Resources & Rate Limiting](https://owasp.org/www-project-api-security). APIs should use the following headers at least on successful responses: - `X-RateLimit-Limit`: number of total requests in a give time window - `X-RateLimit-Remaining`: remaining requests in the current window - `X-RateLimit-Reset`: number of seconds before the window resets An example set of headers is the following ``` X-Ratelimit-Limit: 100 X-Ratelimit-Remaining: 40 X-Ratelimit-Reset: 12 ``` A standardization proposal for ratelimit headers is ongoning inside the IETF HTTPAPI Workgroup. See [the draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/). It requires exactly one of ["X-RateLimit-Limit","RateLimit-Limit"] to be present, and requires exactly one of ["X-RateLimit-Remaining","RateLimit-Remaining"] to be present, and requires exactly one of ["X-RateLimit-Reset","RateLimit-Reset"] to be present (evaluated at `$.[responses][?(@property[0] == "2" )][headers]`). Severity: warn.' message: Missing ratelimit headers. {{property}} {{error}} {{path}} formats: - oas3 severity: warn recommended: true given: $.[responses][?(@property[0] == "2" )][headers] then: - functionOptions: properties: - X-RateLimit-Limit - RateLimit-Limit function: xor - functionOptions: properties: - X-RateLimit-Remaining - RateLimit-Remaining function: xor - functionOptions: properties: - X-RateLimit-Reset - RateLimit-Reset function: xor tags: - source:team-digitale - format:openapi - spec:responses - spec:headers - experience:reliability - experience:security array-require-min-max-items: description: 'Array size should be limited to mitigate resource exhaustion attacks. This can be done using `maxItems` and `minItems`, like in the example below. ``` Limited: type: array maxItems: 10 items: type: string format: date ``` You should ensure that the schema referenced in `items` is constrained too. If you delegate input validation to a library or framework, be sure to test it thoroughly and ensure that it verifies `maxItems`. It requires the `maxItems` field to be defined, and requires the `minItems` field to be defined (evaluated at `$.[?(@.type=="array")]`). Severity: warn.' message: Schema of type array must specify maxItems and minItems. {{path}} {{error}} formats: - oas3 severity: warn recommended: true given: - $.[?(@.type=="array")] then: - field: maxItems function: defined - field: minItems function: defined tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling number-require-min-max: description: 'Numeric values should be limited in size to mitigate resource exhaustion using `maximum` and `minimum`. If you delegate input validation to a library or framework, be sure to test it thoroughly. It requires the `maximum` field to be defined, and requires the `minimum` field to be defined (evaluated at `$.[?(@.type=="number")]`, `$.[?(@.type=="integer")]`). Severity: warn.' message: Schema of type number or integer must specify a maximum and a minimum. {{path}} {{error}} formats: - oas3 severity: warn recommended: true given: - $.[?(@.type=="number")] - $.[?(@.type=="integer")] then: - field: maximum function: defined - field: minimum function: defined tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling object-disallow-additional-properties: description: 'By default, jsonschema allows additionalProperties. This means that schema validators can be bypassed using further, unspecified fields. While forbidding additionalProperties can create rigidity and hinder the evolution of an API - eg making it hard to accept new parameters or fields - it is possible that this flexibility can be used to bypass the schema validator and force the application to process unwanted information. Disable `additionalProperties` with `false` ``` Person: type: object additionalProperties: false properties: given_name: type: string pattern: [a-zA-Z ]{24} ``` Or constraint them using `maxProperties` ``` Person: type: object additionalProperties: type: string pattern: /+39[0-9]{,14}/ maxProperties: 3 properties: given_name: type: string pattern: [a-zA-Z ]{24} ``` - no additionalProperties - constrained additionalProperties. It requires the `additionalProperties` field to be absent or empty (evaluated at `$.[?(@.type=="object" && @.additionalProperties==true)]`). Severity: warn.' message: "Objects should not allow additionalProperties. Disable them with `additionalProperties: false` or constraint them." formats: - oas3 severity: warn recommended: true given: - $.[?(@.type=="object" && @.additionalProperties==true)] then: - field: additionalProperties function: falsy tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling object-set-additional-properties: description: 'By default, jsonschema allows additionalProperties. This means that schema validators can be bypassed using further, unspecified fields. While forbidding additionalProperties can create rigidity and hinder the evolution of an API - eg making it hard to accept new parameters or fields - it is possible that this flexibility can be used to bypass the schema validator and force the application to process unwanted information. Disable `additionalProperties` with `false` ``` Person: type: object additionalProperties: false properties: given_name: type: string pattern: [a-zA-Z ]{24} ``` Or constraint them using `maxProperties` ``` Person: type: object additionalProperties: type: string pattern: /+39[0-9]{,14}/ maxProperties: 3 properties: given_name: type: string pattern: [a-zA-Z ]{24} ``` - no additionalProperties - constrained additionalProperties. It requires the `additionalProperties` field to be defined (evaluated at `$.[?(@.type=="object" && ! @.additionalProperties)]`). Severity: warn.' message: "Objects should not allow additionalProperties. Disable them with `additionalProperties: false` or constraint them." formats: - oas3 severity: warn recommended: true given: - $.[?(@.type=="object" && ! @.additionalProperties)] then: - field: additionalProperties function: defined tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling object-constrain-additional-properties: description: 'By default, jsonschema allows additionalProperties. This means that schema validators can be bypassed using further, unspecified fields. While forbidding additionalProperties can create rigidity and hinder the evolution of an API - eg making it hard to accept new parameters or fields - it is possible that this flexibility can be used to bypass the schema validator and force the application to process unwanted information. Disable `additionalProperties` with `false` ``` Person: type: object additionalProperties: false properties: given_name: type: string pattern: [a-zA-Z ]{24} ``` Or constraint them using `maxProperties` ``` Person: type: object additionalProperties: type: string pattern: /+39[0-9]{,14}/ maxProperties: 3 properties: given_name: type: string pattern: [a-zA-Z ]{24} ``` - no additionalProperties - constrained additionalProperties. It requires the `maxProperties` field to be defined (evaluated at `$.[?(@.type=="object" && @.additionalProperties && @.additionalProperties!=true && @.additionalProperties!=false )]`). Severity: warn.' message: "Objects should not allow additionalProperties. Disable them with `additionalProperties: false` or constraint them." formats: - oas3 severity: warn recommended: true given: - $.[?(@.type=="object" && @.additionalProperties && @.additionalProperties!=true && @.additionalProperties!=false )] then: - field: maxProperties function: defined tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling get-operation-require-security: description: "Your API should be protected by a `security` rule either at global or operation level. Operations should be protected specially when they are tied to non-idempotent HTTP methods like `POST`, `PUT`, `PATCH` and `DELETE`. This is done with one or more non-empty `security` rules. Security rules are defined in the `securityScheme` section. An example of a security rule applied at global level. ``` security: - BasicAuth: [] paths: /books: {} /users: {} securitySchemes: BasicAuth: scheme: http type: basic ``` An example of a security rule applied at operation level, which eventually overrides the global one ``` paths: /books: post: security: - AccessToken: [] securitySchemes: BasicAuth: scheme: http type: basic AccessToken: scheme: http type: bearer bearerFormat: JWT ```. It validates the `security` field against a JSON Schema (evaluated at `$.paths.*.get`). Severity: info." message: "The following operation is not protected by a `security` rule: {{path}}" formats: - oas3 severity: info recommended: true given: - $.paths.*.get then: - field: security function: schema functionOptions: schema: items: type: object minProperties: 1 minItems: 1 type: array tags: - source:team-digitale - format:openapi - spec:paths - spec:operations - experience:security write-operation-require-security: description: "Your API should be protected by a `security` rule either at global or operation level. Operations should be protected specially when they are tied to non-idempotent HTTP methods like `POST`, `PUT`, `PATCH` and `DELETE`. This is done with one or more non-empty `security` rules. Security rules are defined in the `securityScheme` section. An example of a security rule applied at global level. ``` security: - BasicAuth: [] paths: /books: {} /users: {} securitySchemes: BasicAuth: scheme: http type: basic ``` An example of a security rule applied at operation level, which eventually overrides the global one ``` paths: /books: post: security: - AccessToken: [] securitySchemes: BasicAuth: scheme: http type: basic AccessToken: scheme: http type: bearer bearerFormat: JWT ```. It validates the `security` field against a JSON Schema (evaluated at `$.paths.*[?(@property.match(/^(post|put|patch|delete)/))]`). Severity: error." message: "The following non-idempotent operation is not protected by a `security` rule: {{path}}" formats: - oas3 severity: error recommended: true given: - $.paths.*[?(@property.match(/^(post|put|patch|delete)/))] then: - field: security function: schema functionOptions: schema: items: type: object minProperties: 1 minItems: 1 type: array tags: - source:team-digitale - format:openapi - spec:paths - spec:operations - experience:security oauth-scheme-require-description: description: 'Json Web Tokens RFC7519 is a compact, URL-safe means of representing claims to be transferred between two parties. JWT can be enclosed in encrypted or signed tokens like JWS and JWE. The [JOSE IANA registry](https://www.iana.org/assignments/jose/jose.xhtml) provides algorithms information. RFC8725 describes common pitfalls in the JWx specifications and in their implementations, such as: - the ability to ignore algorithms, eg. `{"alg": "none"}`; - using insecure algorithms like `RSASSA-PKCS1-v1_5` eg. `{"alg": "RS256"}`. An API using JWT should explicit in the `description` that the implementation conforms to RFC8725. ``` components: securitySchemes: JWTBearer: type: http scheme: bearer bearerFormat: JWT description: |- A bearer token in the format of a JWS and conformato to the specifications included in RFC8725. ```. It requires the `description` field to be present and non-empty, and requires the `description` field to match the pattern `.*RFC8725.*` (evaluated at `$.[securitySchemes][?(@.type=="oauth2")]`). Severity: warn.' message: JWT usage should be detailed in `description` {{error}}. given: - $.[securitySchemes][?(@.type=="oauth2")] then: - field: description function: truthy - field: description function: pattern functionOptions: match: .*RFC8725.* tags: - source:team-digitale - format:openapi - spec:security - experience:security - experience:documentation jwt-scheme-require-description: description: 'Json Web Tokens RFC7519 is a compact, URL-safe means of representing claims to be transferred between two parties. JWT can be enclosed in encrypted or signed tokens like JWS and JWE. The [JOSE IANA registry](https://www.iana.org/assignments/jose/jose.xhtml) provides algorithms information. RFC8725 describes common pitfalls in the JWx specifications and in their implementations, such as: - the ability to ignore algorithms, eg. `{"alg": "none"}`; - using insecure algorithms like `RSASSA-PKCS1-v1_5` eg. `{"alg": "RS256"}`. An API using JWT should explicit in the `description` that the implementation conforms to RFC8725. ``` components: securitySchemes: JWTBearer: type: http scheme: bearer bearerFormat: JWT description: |- A bearer token in the format of a JWS and conformato to the specifications included in RFC8725. ```. It requires the `description` field to be present and non-empty, and requires the `description` field to match the pattern `.*RFC8725.*` (evaluated at `$.[securitySchemes][?(@.bearerFormat=="jwt" || @.bearerFormat=="JWT")]`). Severity: warn.' message: JWT usage should be detailed in `description` {{error}}. given: - $.[securitySchemes][?(@.bearerFormat=="jwt" || @.bearerFormat=="JWT")] then: - field: description function: truthy - field: description function: pattern functionOptions: match: .*RFC8725.* tags: - source:team-digitale - format:openapi - spec:security - experience:security - experience:documentation oauth-endpoints-require-https: description: 'OAuth2 endpoints must use `https://`. It requires the `value` field to match the pattern `^https://` (evaluated at `$.[securitySchemes][?(@.type=="oauth2")][*].[?(@property.match(/url$/i))]`). Severity: error.' message: OAuth endpoints must use https:// formats: - oas3 severity: error recommended: true given: - $.[securitySchemes][?(@.type=="oauth2")][*].[?(@property.match(/url$/i))] then: - field: value function: pattern functionOptions: match: ^https:// tags: - source:team-digitale - format:openapi - spec:security - experience:security oauth-disallow-insecure-flows: description: 'The OAuth2 authorization framework defines various [grant types](https://tools.ietf.org/html/rfc6749#section-1.3), most notably the [AuthorizationCode](https://tools.ietf.org/html/rfc6749#section-1.3.1) and the [Client Credentials](https://tools.ietf.org/html/rfc6749#section-1.3.4). Some grant types are now considered insecure and MUST not be used, including `implicit` and `password`. The new [OAuth2.1](https://tools.ietf.org/html/draft-ietf-oauth-v2-1-01) still in draft, removes them and suggests to replace the `implicit` with `authorizationCode` + PKCE defined in RFC7636. It requires the `implicit` field to be absent or empty, and requires the `password` field to be absent or empty (evaluated at `$.[?(@.type=="oauth2")].flows`). Severity: error.' message: 'Do not use oauth2 insecure flow: "{{property}}".' formats: - oas3 severity: error recommended: true given: - $.[?(@.type=="oauth2")].flows then: - field: implicit function: falsy - field: password function: falsy tags: - source:team-digitale - format:openapi - spec:document - experience:security string-require-max-length: description: "String length should be limited to avoid an attacker to send very long strings to your service. You can do this in different ways: - specify a `maxLength` - constraint the possible values with an `enum` - use a constrained `format` like `date` or `date-time`. A constrained string using the `date` format. ``` ConstrainedString: type: string format: date ``` Another constrained string using `maxLength`. You can always add further constraints using a `pattern` or a `format`. ``` ZipCode: type: string maxLength: 5 pattern: '[0-9]{5}' ``` For further security, you can always limit string length even in conjunction with `format` and `pattern`. It requires the `maxLength` field to be defined (evaluated at `$.[?(@.type==\"string\" && !@.enum && @.format!=\"date\" && @.format !=\"date-time\" )]`). Severity: warn." message: Strings (non enum) must specify a maximum length. {{path}} {{error}} formats: - oas3 severity: warn recommended: true given: - $.[?(@.type=="string" && !@.enum && @.format!="date" && @.format !="date-time" )] then: - field: maxLength function: defined tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling string-require-pattern-or-format: description: "String length should be limited to avoid an attacker to send very long strings to your service. You can do this in different ways: - specify a `maxLength` - constraint the possible values with an `enum` - use a constrained `format` like `date` or `date-time`. A constrained string using the `date` format. ``` ConstrainedString: type: string format: date ``` Another constrained string using `maxLength`. You can always add further constraints using a `pattern` or a `format`. ``` ZipCode: type: string maxLength: 5 pattern: '[0-9]{5}' ``` For further security, you can always limit string length even in conjunction with `format` and `pattern`. It validates the targeted value against a JSON Schema (evaluated at `$.[?(@.type==\"string\" && !@.enum && @.format!=\"date\" && @.format !=\"date-time\" )]`). Severity: hint." message: Strings (non enum) must specify a pattern or a format. {{path}} formats: - oas3 severity: hint recommended: true given: - $.[?(@.type=="string" && !@.enum && @.format!="date" && @.format !="date-time" )] then: function: schema functionOptions: schema: type: object anyOf: - required: - pattern - required: - format additionalProperties: true tags: - source:team-digitale - format:openapi - spec:document - experience:security - experience:data-modeling server-url-meet-standards: description: "API URLs should meet the Trimble API Standards. It applies a custom validation to the targeted value (evaluated at `$.servers`). Severity: warn." message: "{{error}}" given: $.servers severity: warn then: function: trimble:valid-url-checker tags: - source:trimble - format:openapi - spec:servers - experience:consistency - experience:governance server-url-include-version: description: "API URLs versions should meet the Trimble API Standards. It applies a custom validation to the targeted value (evaluated at `$.servers`). Severity: warn." message: "{{error}}" given: $.servers severity: warn then: function: trimble:valid-version-checker tags: - source:trimble - format:openapi - spec:servers - experience:versioning - experience:consistency schema-properties-camel-case-2: description: "Ensuring that schema property names are camel case. It requires the `@key` field to match the pattern `^[a-z][a-zA-Z0-9]*$` (evaluated at `$..properties.`). Severity: error." message: All schema property names MUST be camel case. severity: error given: $..properties. then: field: "@key" function: pattern functionOptions: match: ^[a-z][a-zA-Z0-9]*$ errorMessage: All field names MUST be formatted as camel case. tags: - source:trimble - format:openapi - spec:schemas - experience:naming - experience:consistency path-no-http-verbs: description: "HTTP verbs should be not be in URL paths. It applies a custom validation to the `@key` field (evaluated at `$.paths`). Severity: warn." message: "{{property}} has HTTP verb in path: {{error}}" recommended: true type: style given: $.paths then: field: "@key" function: trimble:no-http-verbs-in-path tags: - source:trimble - format:openapi - spec:paths - experience:naming - experience:consistency write-response-support-json: description: "All APIs returning structured data SHOULD support JSON as the default format. It applies a custom validation to the targeted value (evaluated at `$.paths.*.`). Severity: error." severity: error message: "{{error}}" given: $.paths.*. then: function: trimble:check-if-application-or-json-in-put-and-post-response tags: - source:trimble - format:openapi - spec:paths - experience:consistency - experience:data-modeling get-response-support-json: description: "All APIs returning structured data SHOULD support JSON as the default format. It applies a custom validation to the targeted value (evaluated at `$.paths.*.`). Severity: warn." severity: warn message: "{{error}}" given: $.paths.*. then: function: trimble:check-if-response-body-json-in-get-response tags: - source:trimble - format:openapi - spec:paths - experience:consistency - experience:data-modeling response-code-must-be-valid: description: "All APIs should return a valid http response code. It applies a custom validation to the `@key` field (evaluated at `$..responses`). Severity: warn." severity: warn message: "{{error}}" given: $..responses then: field: "@key" function: trimble:valid-http-response tags: - source:trimble - format:openapi - spec:responses - experience:error-handling - experience:consistency path-require-query-parameter: description: "Check if the given resource path has queryparameter. It applies a custom validation to the `@key` field (evaluated at `$.paths`). Severity: warn." severity: warn message: "{{error}}" given: $.paths then: field: "@key" function: trimble:check-for-query-parameter-in-every-path tags: - source:trimble - format:openapi - spec:paths - experience:usability - experience:consistency path-require-valid-http-verb: description: "All APIs MUST have a valid http verb. It applies a custom validation to the `@key` field (evaluated at `$.paths.*`). Severity: warn." severity: warn message: "{{error}}" given: $.paths.* then: field: "@key" function: trimble:does-spec-contains-valid-http-verbs tags: - source:trimble - format:openapi - spec:paths - experience:consistency - experience:governance spec-must-not-be-empty: description: "Spec should not be empty. It applies a custom validation to the targeted value (evaluated at `$`). Severity: error." severity: error message: "{{error}}" given: $ then: function: trimble:is-valid-spec tags: - source:trimble - format:openapi - spec:document - experience:governance tag-no-pascal-case: severity: warn recommended: true message: Tag names cannot use Pascal Case. Please rename {{value}}. given: - $.tags[*].name - $.paths[*][*].tags[*] then: function: pattern functionOptions: notMatch: /[A-Z][a-z]+[A-Z][a-z]+$/g tags: - source:trimble - format:openapi - spec:paths - spec:tags - experience:naming - experience:consistency description: "Tag names cannot use Pascal Case. Please rename {{value}}. It requires the targeted value not to match `/[A-Z][a-z]+[A-Z][a-z]+$/g` (evaluated at `$.tags[*].name`, `$.paths[*][*].tags[*]`). Severity: warn." tag-no-camel-case: description: "Detects a tag with camelCase (personalItem) text within it. It requires the targeted value not to match `/^[a-z]+[A-Z][a-z]+$/g` (evaluated at `$.tags[*].name`, `$.paths[*][*].tags[*]`). Severity: warn." severity: warn recommended: true message: Tag names cannot use Camel Case. Please rename {{value}}. given: - $.tags[*].name - $.paths[*][*].tags[*] then: function: pattern functionOptions: notMatch: /^[a-z]+[A-Z][a-z]+$/g tags: - source:trimble - format:openapi - spec:paths - spec:tags - experience:naming - experience:consistency tag-no-version-info: severity: warn recommended: true message: Tag names cannot have version information {{value}}. Consider versioning your API. given: - $.tags[*].name - $.paths[*][*].tags[*] then: function: pattern functionOptions: notMatch: /(V|v)\s?[0-9]+/g tags: - source:trimble - format:openapi - spec:paths - spec:tags - experience:naming - experience:versioning description: "Tag names cannot have version information {{value}}. Consider versioning your API. It requires the targeted value not to match `/(V|v)\\s?[0-9]+/g` (evaluated at `$.tags[*].name`, `$.paths[*][*].tags[*]`). Severity: warn." operation-summary-description-differ: description: "Operation summaries and description should not match. It applies a custom validation to the targeted value (evaluated at `$.paths[*].[get,post,put,patch,delete]`). Severity: warn." message: "{{error}}" severity: warn formats: - oas3 given: - $.paths[*].[get,post,put,patch,delete] then: function: trimble:operation-summary-description tags: - source:trimble - format:openapi - spec:paths - spec:operations - experience:documentation delete-require-204-response: description: "All DELETE methods MUST have a 204 response. It requires the `204` field to be present and non-empty (evaluated at `$.paths[*].delete.responses`). Severity: error." severity: error recommended: true formats: - oas3 given: - $.paths[*].delete.responses then: field: "204" function: truthy tags: - source:trimble - format:openapi - spec:paths - spec:operations - spec:responses - experience:consistency - experience:error-handling post-require-201-or-202-response: description: "All POST methods MUST have a 201 or 202 response. It applies a custom validation to the targeted value (evaluated at `$.paths[*].post.responses`). Severity: error." severity: error recommended: true formats: - oas3 given: - $.paths[*].post.responses then: function: trimble:operation-post-201-202-status-code tags: - source:trimble - format:openapi - spec:paths - spec:operations - spec:responses - experience:consistency - experience:error-handling response-400-require-body: description: "All 400 responses must include a response body. It requires the `content` field to be present and non-empty (evaluated at `$.paths.*.*.responses['400']`). Severity: error." severity: error recommended: true formats: - oas3 given: - $.paths.*.*.responses['400'] then: field: content function: truthy tags: - source:trimble - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:documentation response-206-require-content-range: description: "Check if the get response code 206 has content-type and content-range. It applies a custom validation to the targeted value (evaluated at `$.paths.*.`). Severity: warn." severity: warn message: "{{error}}" given: $.paths.*. then: function: trimble:check-content-type-for-206-get-response-code tags: - source:trimble - format:openapi - spec:paths - experience:consistency - experience:data-modeling error-response-standard-payload: description: "All 4XX and 5XX response codes must follow Trimble API Standard. It applies a custom validation to the targeted value (evaluated at `$.paths.*.*.responses.`). Severity: error." severity: error given: $.paths.*.*.responses. message: "{{error}}" then: function: trimble:check-standard-for-error-payload tags: - source:trimble - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:consistency error-response-require-description: description: "Check if the response description is appropriate for all requests. It applies a custom validation to the targeted value (evaluated at `$.paths.*.*.responses.`). Severity: warn." severity: warn message: "{{error}}" given: $.paths.*.*.responses. then: function: trimble:check-description-for-all-error-responses tags: - source:trimble - format:openapi - spec:paths - spec:responses - experience:documentation - experience:error-handling success-response-require-description: description: "Check if the response description is appropriate for all requests. It applies a custom validation to the targeted value (evaluated at `$.paths.*.`). Severity: warn." severity: warn message: "{{error}}" given: $.paths.*. then: function: trimble:check-description-for-all-success-responses tags: - source:trimble - format:openapi - spec:paths - experience:documentation write-response-require-content-type: description: "All API responses MUST include the Content-Type header in all responses. It applies a custom validation to the targeted value (evaluated at `$.paths[*].post.responses`, `$.paths[*].put.responses`). Severity: error." severity: error message: "{{error}}" given: - $.paths[*].post.responses - $.paths[*].put.responses then: function: trimble:check-for-content-type-in-put-and-post-responses tags: - source:trimble - format:openapi - spec:paths - spec:operations - spec:responses - experience:consistency - experience:data-modeling path-params-declared-in-block: description: "Check for the path parameter in the parameter block. It applies a custom validation to the targeted value (evaluated at `$.paths.`). Severity: error." severity: error message: "{{error}}" given: $.paths. then: function: trimble:check-for-path-parameter tags: - source:trimble - format:openapi - spec:paths - experience:consistency - experience:documentation operation-require-response: description: "Check if every request has their respective responses. It applies a custom validation to the targeted value (evaluated at `$.paths.*`). Severity: error." severity: error message: "{{error}}" given: $.paths.* then: function: trimble:check-for-response-in-every-request tags: - source:trimble - format:openapi - spec:paths - experience:documentation - experience:consistency delete-no-response-body: description: "Check if the delete response does not have any body. It applies a custom validation to the targeted value (evaluated at `$.paths.*.`). Severity: warn." severity: warn message: "{{error}}" given: $.paths.*. then: function: trimble:delete-must-not-return-body tags: - source:trimble - format:openapi - spec:paths - experience:consistency - experience:data-modeling path-no-invalid-symbols: description: "Check if the given endpoint has queryparameter. It applies a custom validation to the `@key` field (evaluated at `$.paths.`). Severity: error." severity: error message: "{{error}}" given: $.paths. then: field: "@key" function: trimble:invalid-symbol-in-path tags: - source:trimble - format:openapi - spec:paths - experience:naming - experience:consistency no-http-basic-auth: description: "Consider a more secure alternative to HTTP Basic. It requires the `scheme` field not to match `basic` (evaluated at `$.components.securitySchemes[*]`). Severity: error." message: HTTP Basic is an insecure way to pass credentials around, use an alternative. severity: error given: $.components.securitySchemes[*] then: field: scheme function: pattern functionOptions: notMatch: basic tags: - source:sps-commerce - format:openapi - spec:security - spec:components - experience:security collection-response-support-paging: description: "Response bodies from collection endpoints SHOULD offer paging capability. It requires the `paging` field to be present and non-empty, and requires the `paging` field to match the pattern `object`, and requires the `paging.type` field to match the pattern `object` (evaluated at `$.paths[?(!@property.match(/.*\\/\\{[^}]+\\}.*$/))].get.responses['200']\ .content.application/json.schema.properties`). Severity: warn." severity: warn given: $.paths[?(!@property.match(/.*\/\{[^}]+\}.*$/))].get.responses['200'].content.application/json.schema.properties then: - field: paging function: truthy - field: paging function: pattern functionOptions: match: object - field: paging.type function: pattern functionOptions: match: object tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - spec:schemas - experience:pagination - experience:usability collection-require-results-array: description: "Response bodies must have a root element called results and is an array of objects. It requires the `type` field to match the pattern `array`, and requires the `items.type` field to match the pattern `object` (evaluated at `$.paths[?(!@property.match(/.*\\/\\{[^}]+\\}$/))].get.responses['200'].c\ ontent.application/json.schema.properties.results`). Severity: error." severity: error given: $.paths[?(!@property.match(/.*\/\{[^}]+\}$/))].get.responses['200'].content.application/json.schema.properties.results then: - field: type function: pattern functionOptions: match: array - field: items.type function: pattern functionOptions: match: object tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - spec:schemas - experience:pagination - experience:data-modeling collection-require-pagination-params: description: "Collection GET endpoints SHOULD support pagination using query parameters. Offset or cursor based pagination is required. It validates the `parameters` field against a JSON Schema (evaluated at `$.paths[?(!@property.match(/.*\\/\\{[^}]+\\}\\/*.*/))].get`). Severity: warn." severity: warn given: $.paths[?(!@property.match(/.*\/\{[^}]+\}\/*.*/))].get then: - field: parameters function: schema functionOptions: schema: type: array items: type: object contains: type: object properties: name: const: limit in: const: query allOf: - anyOf: - contains: type: object properties: name: const: offset in: const: query - contains: type: object properties: name: const: cursor in: const: query tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - experience:pagination - experience:usability post-collection-require-paging-object: description: "POST collection endpoints MUST have a request body schema that includes paging parameters. It requires the `type` field to match the pattern `object` (evaluated at `$.paths[?(!@property.match(/.*\\/\\{[^}]+\\}$/))].post.requestBody.conte\ nt.application/json.schema.properties.paging`). Severity: error." severity: error given: $.paths[?(!@property.match(/.*\/\{[^}]+\}$/))].post.requestBody.content.application/json.schema.properties.paging then: field: type function: pattern functionOptions: match: object tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:request-body - spec:media-types - spec:schemas - experience:pagination - experience:data-modeling no-id-query-parameter: description: "Resource identifier filtering is not allowed as a query parameter. Use the resource identifier in the URL path. It requires the `name` field not to match `^id$` (evaluated at `$.paths..get.parameters.[?(@.in=='query' && @.name=='id')]`). Severity: warn." severity: warn given: $.paths..get.parameters.[?(@.in=='query' && @.name=='id')] then: field: name function: pattern functionOptions: notMatch: ^id$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:parameters - experience:consistency - experience:usability filter-param-only-on-get: description: "Only GET-based endpoints SHOULD have have the query parameter 'filter'. It requires the targeted value to be absent or empty (evaluated at `$.paths.*[?(@property!='get')].parameters.[?(@.in=='query' && @.name=='filter')].name`). Severity: error." severity: error given: $.paths.*[?(@property!='get')].parameters.[?(@.in=='query' && @.name=='filter')].name then: function: falsy tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:parameters - experience:consistency - experience:usability no-hybrid-and-root-filtering: description: 'Hybrid filtering MAY be offered on multiple attributes, but MUST never exist if a root "filter" query parameter is present. It validates the targeted value against a JSON Schema (evaluated at `$.paths..get.parameters^`). Severity: error.' severity: error given: $.paths..get.parameters^ then: function: schema functionOptions: schema: type: object properties: parameters: type: array items: type: object properties: name: type: string in: type: string allOf: - if: properties: parameters: type: array contains: type: object properties: name: const: filter then: not: properties: parameters: type: array contains: type: object properties: name: type: string pattern: \w+Filter tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:parameters - experience:consistency - experience:usability sort-param-only-on-get: description: "Non-GET endpoints MUST NOT have sorting query parameters. Parameter names such as sort, sorting, orderBy, etc. It requires the `name` field not to match `^sort|sorting|sortBy|order|ordering|orderBy$` (evaluated at `$.paths.*[?(@property!='get')].parameters.[?(@.in=='query')]`). Severity: error." severity: error given: $.paths.*[?(@property!='get')].parameters.[?(@.in=='query')] then: field: name function: pattern functionOptions: notMatch: ^sort|sorting|sortBy|order|ordering|orderBy$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:parameters - experience:consistency - experience:usability error-response-use-problem-type-2: description: 'Every error response SHOULD support RFC 9457. It requires the targeted value to be one of ["application/problem+xml","application/problem+json"] (evaluated at `$.paths...responses[?(@property.match(/^(4|5)/))].content.*~`). Severity: error.' severity: error given: $.paths...responses[?(@property.match(/^(4|5)/))].content.*~ then: function: enumeration functionOptions: values: - application/problem+xml - application/problem+json tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:media-types - experience:error-handling - experience:consistency property-no-language-keywords: description: "Names that may conflict with keywords in common programming languages SHOULD NOT be used. It requires the targeted value not to match `^(abstract|for|new|switch|assert|default|goto|package|synchronized|boole\ an|do|if|private|this|break|double|implements|throw|byte|else|import|publ\ ic|throws|case|enum|instanceof|return|transient|catch|extends|int|short|t\ ry|char|final|interface|static|void|class|finally|long|volatile|const|flo\ at|native|super|while)$` (evaluated at `$..properties.*~`). Severity: warn." severity: warn given: $..properties.*~ then: function: pattern functionOptions: notMatch: ^(abstract|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|volatile|const|float|native|super|while)$ tags: - source:sps-commerce - format:openapi - spec:schemas - experience:naming - experience:consistency property-names-camel-case-2: description: "Property names and acronyms MUST be in camelCase. It requires the targeted value to match the pattern `^[a-z][a-z0-9]*(([A-Z]{2}|[A-Z])[a-z0-9]+)*$` (evaluated at `$..properties.*~`). Severity: error." severity: error formats: - oas3 given: $..properties.*~ then: function: pattern functionOptions: match: ^[a-z][a-z0-9]*(([A-Z]{2}|[A-Z])[a-z0-9]+)*$ tags: - source:sps-commerce - format:openapi - spec:schemas - experience:naming - experience:consistency property-no-prepositions: description: 'Property names SHOULD NOT include prepositions (e.g. "for", "during", "at", etc.). It requires the targeted value not to match `(^(about|above|across|after|against|among|around|at|before|behind|below|beside|between|down|during|for|from|in|inside|into|near|of|off|on|out|over|through|to|toward|under|up|with|as|but|like|since|than|till|unlike|until|upon|within|without)([A-Z]|$)|.*(About|Above|Across|After|Against|Among|Around|At|Before|Behind|Below|Beside|Between|Down|During|For|From|In|Inside|Into|Near|Of|Off|On|Out|Over|Through|To|Toward|Under|Up|With|As|But|Like|Since|Than|Till|Unlike|Until|Upon|Within|Without)([A-Z]|$)).*` (evaluated at `$..properties.*~`). Severity: warn.' severity: warn formats: - oas3 given: $..properties.*~ then: function: pattern functionOptions: notMatch: (^(about|above|across|after|against|among|around|at|before|behind|below|beside|between|down|during|for|from|in|inside|into|near|of|off|on|out|over|through|to|toward|under|up|with|as|but|like|since|than|till|unlike|until|upon|within|without)([A-Z]|$)|.*(About|Above|Across|After|Against|Among|Around|At|Before|Behind|Below|Beside|Between|Down|During|For|From|In|Inside|Into|Near|Of|Off|On|Out|Over|Through|To|Toward|Under|Up|With|As|But|Like|Since|Than|Till|Unlike|Until|Upon|Within|Without)([A-Z]|$)).* tags: - source:sps-commerce - format:openapi - spec:schemas - experience:naming - experience:consistency boolean-no-prefix: description: "Boolean properties SHOULD NOT use is, has, or another prefix. It requires the targeted value not to match `^(is|has|was|will|needs|uses|should|can)([A-Z]|$).*` (evaluated at `$..properties[?(@ && @.type == 'boolean')]~`). Severity: warn." severity: warn formats: - oas3 given: $..properties[?(@ && @.type == 'boolean')]~ then: function: pattern functionOptions: notMatch: ^(is|has|was|will|needs|uses|should|can)([A-Z]|$).* tags: - source:sps-commerce - format:openapi - spec:schemas - experience:naming - experience:consistency ref-property-require-format: description: "Property with the name 'ref' MUST use a format 'sps-ref'. It requires the `format` field to be present and non-empty, and requires the `format` field to match the pattern `^sps-ref$` (evaluated at `$..properties..[?((@property=== \"ref\" || @property === \"Ref\") && @.$ref == null && @.allOf == null && @.oneOf == null && @.type != null)]`). Severity: error." severity: error formats: - oas3 given: $..properties..[?((@property=== "ref" || @property === "Ref") && @.$ref == null && @.allOf == null && @.oneOf == null && @.type != null)] resolved: false then: - field: format function: truthy - field: format function: pattern functionOptions: match: ^sps-ref$ tags: - source:sps-commerce - format:openapi - spec:schemas - experience:data-modeling - experience:consistency ref-property-standard-schema: description: "Properties following 'sps-ref' format MUST use the standardized schema - maxLength (255), minLength(7), pattern (includes 'sps'), type (string). It validates the targeted value against a JSON Schema, and requires the `pattern` field to match the pattern `sps`, and requires the `type` field to match the pattern `^string$` (evaluated at `$..[?(@property=== \"format\" && @ == \"sps-ref\")]^`). Severity: error." message: "{{property}} is not provided or not following required schema values." severity: error formats: - oas3 given: $..[?(@property=== "format" && @ == "sps-ref")]^ then: - function: schema functionOptions: schema: type: object required: - maxLength - minLength - type - pattern properties: maxLength: type: integer minimum: 255 maximum: 255 minLength: type: integer minimum: 7 maximum: 7 type: type: string pattern: type: string - field: pattern function: pattern functionOptions: match: sps - field: type function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency id-property-must-be-string: description: "id SHOULD use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"id\")].type`). Severity: warn." severity: warn formats: - oas3 given: $..[?(@property === "id")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency use-id-not-identifier: description: "Use abbreviations instead of long form names, i.e. identifier SHOULD BE id. It requires the targeted value not to match `^identifier$` (evaluated at `$..properties.*~`). Severity: warn." severity: warn formats: - oas3 given: $..properties.*~ then: function: pattern functionOptions: notMatch: ^identifier$ tags: - source:sps-commerce - format:openapi - spec:schemas - experience:naming - experience:consistency use-org-not-organization: description: "Use abbreviations instead of long form names, i.e. organization SHOULD BE org. It requires the targeted value not to match `(^organization([A-Z]|$)|Organization([A-Z]|$))` (evaluated at `$..properties.*~`). Severity: warn." severity: warn formats: - oas3 given: $..properties.*~ then: function: pattern functionOptions: notMatch: (^organization([A-Z]|$)|Organization([A-Z]|$)) tags: - source:sps-commerce - format:openapi - spec:schemas - experience:naming - experience:consistency ref-property-must-be-string: description: "ref MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"ref\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "ref")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency orgid-property-must-be-string: description: "orgId MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"orgId\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "orgId")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency name-property-must-be-string: description: "name MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"name\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "name")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency description-property-must-be-string: description: "description MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"description\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "description")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency requestid-property-must-be-string: description: "requestId MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"requestId\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "requestId")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency created-datetime-must-be-date-time: description: "createdDateTime MUST use a data type of 'string' with the format 'date-time'. It requires the `type` field to match the pattern `^string$`, and requires the `format` field to be present and non-empty, and requires the `format` field to match the pattern `^date-time$` (evaluated at `$..properties.createdDateTime`). Severity: error." severity: error formats: - oas3 given: $..properties.createdDateTime then: - field: type function: pattern functionOptions: match: ^string$ - field: format function: truthy - field: format function: pattern functionOptions: match: ^date-time$ tags: - source:sps-commerce - format:openapi - spec:schemas - experience:data-modeling - experience:consistency createdby-property-must-be-string: description: "createdBy MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"createdBy\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "createdBy")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency modified-datetime-must-be-date-time: description: "modifiedDateTime MUST use a data type of 'string' with the format 'date-time'. It requires the `type` field to match the pattern `^string$`, and requires the `format` field to be present and non-empty, and requires the `format` field to match the pattern `^date-time$` (evaluated at `$..properties.modifiedDateTime`). Severity: error." severity: error formats: - oas3 given: $..properties.modifiedDateTime then: - field: type function: pattern functionOptions: match: ^string$ - field: format function: truthy - field: format function: pattern functionOptions: match: ^date-time$ tags: - source:sps-commerce - format:openapi - spec:schemas - experience:data-modeling - experience:consistency modifiedby-property-must-be-string: description: "modifiedBy MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"modifiedBy\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "modifiedBy")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency deletedby-property-must-be-string: description: "deletedBy MUST use a data type of 'string'. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === \"deletedBy\")].type`). Severity: error." severity: error formats: - oas3 given: $..[?(@property === "deletedBy")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency fingerprint-property-must-be-string: description: 'Fingerprint values MUST use a data type of `string`. It requires the targeted value to match the pattern `^string$` (evaluated at `$..[?(@property === "fingerprint")].type`). Severity: error.' severity: error formats: - oas3 given: $..[?(@property === "fingerprint")].type then: function: pattern functionOptions: match: ^string$ tags: - source:sps-commerce - format:openapi - spec:document - experience:data-modeling - experience:consistency use-fingerprint-not-hash: description: "Rather than property names refering to the implementation for 'hash' or 'hashkey', you MUST use the property name 'fingerprint'. It requires the targeted value not to match `^hashkey|hashKey|hash$` (evaluated at `$.components.schemas..properties.*~`). Severity: error." message: "{{property}} is not using property name fingerprint." severity: error formats: - oas3 given: $.components.schemas..properties.*~ then: function: pattern functionOptions: notMatch: ^hashkey|hashKey|hash$ tags: - source:sps-commerce - format:openapi - spec:schemas - spec:components - experience:naming - experience:consistency response-body-must-be-object: description: "Response bodies must be an object type. It requires the targeted value to match the pattern `object` (evaluated at `$.paths[*][*].responses[*].content.application/json.schema.type`). Severity: error." severity: error given: $.paths[*][*].responses[*].content.application/json.schema.type then: function: pattern functionOptions: match: object tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:media-types - spec:schemas - experience:data-modeling - experience:consistency use-standard-status-codes-2: description: 'An API MUST return HTTP response codes in conformance with RFC-2616 and common usage. It requires the targeted value to be one of ["200","201","202","204","400","401","403","404","405","406","409","412","415","428","429","500"] (evaluated at `$.paths...responses.*~`). Severity: error.' severity: error given: $.paths...responses.*~ then: function: enumeration functionOptions: values: - "200" - "201" - "202" - "204" - "400" - "401" - "403" - "404" - "405" - "406" - "409" - "412" - "415" - "428" - "429" - "500" tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - experience:error-handling - experience:consistency operation-define-500-response: description: "Every endpoint SHOULD have a 500 response. It requires the `responses.500` field to be present and non-empty (evaluated at `$.paths[*][*]`). Severity: warn." severity: warn given: $.paths[*][*] then: field: responses.500 function: truthy tags: - source:sps-commerce - format:openapi - spec:paths - experience:error-handling - experience:reliability no-x-prefixed-request-headers: description: "Do not use headers with X-. It requires the targeted value not to match `^(x|X)-` (evaluated at `$..parameters.[?(@.in === 'header')].name`). Severity: warn." severity: warn message: "Headers cannot start with X-. More: https://tools.ietf.org/html/rfc6648" given: $..parameters.[?(@.in === 'header')].name then: function: pattern functionOptions: notMatch: ^(x|X)- tags: - source:sps-commerce - format:openapi - spec:parameters - spec:headers - experience:naming - experience:consistency no-x-prefixed-response-headers: description: "Do not use headers with X-. It requires the targeted value not to match `^(x|X)-` (evaluated at `$..headers.*~`). Severity: warn." severity: warn message: "Headers cannot start with X-, so please find a new name for {{property}}. More: https://tools.ietf.org/html/rfc6648" given: $..headers.*~ then: function: pattern functionOptions: notMatch: ^(x|X)- tags: - source:sps-commerce - format:openapi - spec:headers - experience:naming - experience:consistency location-header-only-on-201: description: "Location header MUST NOT be present in non-201 responses. It requires the `Location` field to be absent or empty (evaluated at `$.paths[*][*].responses[?(@property !== '201')].headers`). Severity: error." severity: error given: $.paths[*][*].responses[?(@property !== '201')].headers then: field: Location function: falsy tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:headers - experience:consistency - experience:error-handling require-root-security-scheme: description: "Security field MUST be present at the root of the spec with at least one item (ie. HTTPBearer, Token, APIKey, etc.). It validates the `security` field against a JSON Schema (evaluated at `$`). Severity: error." severity: error given: $ then: field: security function: schema functionOptions: schema: type: array minItems: 1 tags: - source:sps-commerce - format:openapi - spec:document - experience:security - experience:governance default-content-language-en-us: description: "Content-Language is optional but MUST default locale to en-US when none provided. It requires the targeted value to match the pattern `en-US` (evaluated at `$.paths[*][*].responses[*].headers.Content-Language.schema.default`). Severity: error." severity: error given: $.paths[*][*].responses[*].headers.Content-Language.schema.default then: function: pattern functionOptions: match: en-US tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:headers - spec:media-types - spec:schemas - experience:consistency - experience:usability no-operational-headers-in-spec: description: "Access-Control-*, Content-Type, and Accept Headers SHOULD NOT be specified explicitly in a spec as it an operational concern. It requires the targeted value not to match `^(Access-Control-.*|Content-Type|Accept)$` (evaluated at `$.paths[*][*].responses[*].headers`). Severity: warn." severity: warn given: $.paths[*][*].responses[*].headers then: function: pattern functionOptions: notMatch: ^(Access-Control-.*|Content-Type|Accept)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:headers - experience:consistency - experience:governance custom-header-naming-format: description: "Custom headers MUST NOT be longer than 50 chars, and MUST only contain alphanumeric and dash chars, and MUST begin with Sps- not X-. It requires the targeted value to match the pattern `^(Sps-[a-zA-Z0-9-]{1,50}|Accept|Access-Control.*|Authorization|Cache-Con\ trol|Content-Disposition|Content-Language|Content-Length|Content-Type|Dat\ e|ETag|Host|If-Match|If-None-Match|Location|Origin|User-Agent)$` (evaluated at `$.paths[*][*].responses[*].headers.*~`). Severity: error." severity: error given: $.paths[*][*].responses[*].headers.*~ then: function: pattern functionOptions: match: ^(Sps-[a-zA-Z0-9-]{1,50}|Accept|Access-Control.*|Authorization|Cache-Control|Content-Disposition|Content-Language|Content-Length|Content-Type|Date|ETag|Host|If-Match|If-None-Match|Location|Origin|User-Agent)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:headers - experience:naming - experience:consistency no-sensitive-data-in-headers: description: "Headers MUST NOT contain sensitive data. It requires the targeted value not to match `^(SPS-Token|SPS-Password|SPS-Identity|Password)$` (evaluated at `$.paths[*][*].responses[*].headers.*~`). Severity: error." severity: error given: $.paths[*][*].responses[*].headers.*~ then: function: pattern functionOptions: notMatch: ^(SPS-Token|SPS-Password|SPS-Identity|Password)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:headers - experience:security - experience:governance no-format-extensions-in-paths: description: "Request and Response media type formats MUST NOT be implied using extensions on resources (i.e. .json or .xml). Instead, use the standard resource path with the appropriate Content-Type header. It requires the targeted value not to match `\\.json|\\.xml|\\.yml|\\.yaml` (evaluated at `$.paths.*~`). Severity: error." severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: \.json|\.xml|\.yml|\.yaml tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency use-standard-mime-types: description: "MIME types MUST be standard (application/json, application/problem+json, application/problem+xml) or use custom format application/vnd.*. It requires the targeted value to match the pattern `^application/(json|problem\\+json|problem\\+xml|vnd\\..*)$` (evaluated at `$.paths[*][*].responses[*].content.*~`). Severity: error." severity: error given: $.paths[*][*].responses[*].content.*~ then: function: pattern functionOptions: match: ^application/(json|problem\+json|problem\+xml|vnd\..*)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:responses - spec:media-types - experience:consistency - experience:data-modeling use-standard-http-methods: description: 'Operations MUST use only the common HTTP methods as outlined in the standards guide, and must be in lower-case. It requires the `method` field to be one of ["get","post","put","patch","delete","head","options"] (evaluated at `$.paths[*].*~`). Severity: error.' severity: error given: $.paths[*].*~ then: field: method function: enumeration functionOptions: values: - get - post - put - patch - delete - head - options tags: - source:sps-commerce - format:openapi - spec:paths - experience:consistency - experience:naming get-must-not-have-request-body: description: "A `GET` request MUST NOT accept a request body. It requires the targeted value to be undefined (evaluated at `$.paths[*][get].requestBody`). Severity: error." severity: error given: $.paths[*][get].requestBody then: function: undefined tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:request-body - experience:consistency - experience:reliability get-must-return-response-body: description: "A `GET` operation must return a response body. It requires the `content` field to be present and non-empty (evaluated at `$.paths[*].get.responses[*]`). Severity: error." severity: error given: $.paths[*].get.responses[*] then: field: content function: truthy tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:consistency - experience:reliability get-response-codes-allowed: description: "GET operations should not use status codes 201, 202, 204, 409, 412. It requires the `@key` field not to match `^(201|202|204|409|412)$` (evaluated at `$.paths[*].get.responses`). Severity: warn." severity: warn given: $.paths[*].get.responses then: field: "@key" function: pattern functionOptions: notMatch: ^(201|202|204|409|412)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency get-must-return-200: description: "GET operations must always return 200 status code. It requires the `200` field to be present and non-empty (evaluated at `$.paths[*].get.responses`). Severity: error." severity: error given: $.paths[*].get.responses then: - field: "200" function: truthy tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency post-response-codes-allowed: description: "POST operations should not return 412 status codes. It requires the `@key` field not to match `412` (evaluated at `$.paths[*].post.responses`). Severity: warn." given: $.paths[*].post.responses severity: warn then: field: "@key" function: pattern functionOptions: notMatch: "412" tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency put-response-codes-allowed: description: "PUT operations should not return 200 or 201 status codes. It requires the `@key` field not to match `^(200|201)$` (evaluated at `$.paths[*].put.responses`). Severity: warn." severity: warn given: $.paths[*].put.responses then: field: "@key" function: pattern functionOptions: notMatch: ^(200|201)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency delete-response-codes-allowed: description: "DELETE operations should not return 200 or 201 status codes. It requires the `@key` field not to match `^(200|201)$` (evaluated at `$.paths[*].delete.responses`). Severity: warn." severity: warn given: $.paths[*].delete.responses then: field: "@key" function: pattern functionOptions: notMatch: ^(200|201)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency delete-must-not-have-request-body: description: "DELETE operations must not accept a request body. It requires the targeted value to be undefined (evaluated at `$.paths[*].delete.requestBody`). Severity: error." severity: error given: $.paths[*].delete.requestBody then: function: undefined tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:request-body - experience:consistency - experience:reliability delete-must-not-return-body: description: "DELETE operations must not have a response body. It requires the targeted value to be absent or empty (evaluated at `$.paths.*.delete.responses[202,204].content`). Severity: error." severity: error given: $.paths.*.delete.responses[202,204].content then: function: falsy tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - experience:consistency - experience:reliability patch-response-codes-allowed: description: "PATCH operations should not return 201 status code. It requires the `@key` field not to match `^201$` (evaluated at `$.paths[*].patch.responses`). Severity: warn." severity: warn given: $.paths[*].patch.responses then: field: "@key" function: pattern functionOptions: notMatch: ^201$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency patch-must-have-request-body: description: "PATCH operations must have a request body. It validates the `requestBody` field against a JSON Schema (evaluated at `$.paths[*].patch`). Severity: error." severity: error given: $.paths[*].patch then: field: requestBody function: schema functionOptions: schema: type: object tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - experience:consistency - experience:reliability head-response-codes-allowed: description: "HEAD operations should not return 201, 202, 204, 409, 412 status codes. It requires the `@key` field not to match `^(201|202|204|409|412)$` (evaluated at `$.paths[*].head.responses`). Severity: warn." severity: warn given: $.paths[*].head.responses then: field: "@key" function: pattern functionOptions: notMatch: ^(201|202|204|409|412)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency head-must-not-have-request-body: description: "A `HEAD` request MUST NOT accept a request body. It requires the targeted value to be undefined (evaluated at `$.paths[*][head].requestBody`). Severity: error." severity: error given: $.paths[*][head].requestBody then: function: undefined tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:request-body - experience:consistency - experience:reliability head-must-not-return-body: description: "HEAD operations should not return a response body for success. It requires the targeted value to be absent or empty (evaluated at `$.paths.*.head.responses[200].content`). Severity: error." given: $.paths.*.head.responses[200].content severity: error then: function: falsy tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - experience:consistency - experience:reliability options-response-codes-allowed: description: "OPTIONS operations should not return 201, 202, 409, 412 status codes. It requires the `@key` field not to match `^(201|202|409|412)$` (evaluated at `$.paths[*].options.responses`). Severity: warn." severity: warn given: $.paths[*].options.responses then: field: "@key" function: pattern functionOptions: notMatch: ^(201|202|409|412)$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - experience:error-handling - experience:consistency options-must-not-have-request-body: description: "An `OPTIONS` request MUST NOT accept a request body. It requires the targeted value to be undefined (evaluated at `$.paths[*][options].requestBody`). Severity: error." severity: error given: $.paths[*][options].requestBody then: function: undefined tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:request-body - experience:consistency - experience:reliability options-must-not-return-body: description: "OPTIONS operations should not return a response body for success. It requires the targeted value to be absent or empty (evaluated at `$.paths.*.options.responses[200, 204].content`). Severity: error." given: $.paths.*.options.responses[200, 204].content severity: error then: function: falsy tags: - source:sps-commerce - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - experience:consistency - experience:reliability request-support-json-media-type-2: description: "Every request MUST support `application/json` media type. It validates the targeted value against a JSON Schema (evaluated at `$.paths[*][*].requestBody.content`). Severity: error." formats: - oas3 severity: error given: $.paths[*][*].requestBody.content then: function: schema functionOptions: schema: type: object properties: application/json: true required: - application/json tags: - source:sps-commerce - format:openapi - spec:paths - spec:request-body - spec:media-types - experience:consistency - experience:usability avoid-integer-id-parameters: description: 'Avoid exposing IDs as an integer, UUIDs or other interoperable strings are preferred. It validates the targeted value against a JSON Schema (evaluated at `$.paths..parameters[*].[?(@property === "name" && (@ === "id" || @ === "ID" || @ === "Id"))]^.schema`). Severity: warn.' severity: warn given: $.paths..parameters[*].[?(@property === "name" && (@ === "id" || @ === "ID" || @ === "Id"))]^.schema then: function: schema functionOptions: schema: type: object not: properties: type: const: integer properties: format: const: uuid tags: - source:sps-commerce - format:openapi - spec:paths - spec:parameters - spec:schemas - experience:security - experience:data-modeling version-must-use-semver: severity: warn message: Version should use semantic versioning. {{value}} is not a valid version. given: $.info.version then: function: pattern functionOptions: match: ^([0-9]+.[0-9]+.[0-9]+)$ tags: - source:sps-commerce - format:openapi - spec:info - experience:versioning - experience:consistency description: "Version should use semantic versioning. {{value}} is not a valid version. It requires the targeted value to match the pattern `^([0-9]+.[0-9]+.[0-9]+)$` (evaluated at `$.info.version`). Severity: warn." schema-names-pascal-case: severity: warn description: "Schema names SHOULD be written in PascalCase. It requires the targeted value to match the pattern `^[A-Z][a-zA-Z0-9]*$` (evaluated at `$.components.schemas.*~`). Severity: warn." message: "{{property}} is not PascalCase: {{error}}" recommended: true type: style given: $.components.schemas.*~ then: function: pattern functionOptions: match: ^[A-Z][a-zA-Z0-9]*$ tags: - source:sps-commerce - format:openapi - spec:schemas - spec:components - experience:naming - experience:consistency response-names-pascal-case: severity: warn description: "Response names SHOULD be written in PascalCase. It requires the targeted value to match the pattern `^[A-Z][a-zA-Z0-9]*$` (evaluated at `$.components.responses.*~`). Severity: warn." message: "{{property}} is not PascalCase: {{error}}" recommended: true type: style given: $.components.responses.*~ then: function: pattern functionOptions: match: ^[A-Z][a-zA-Z0-9]*$ tags: - source:sps-commerce - format:openapi - spec:responses - spec:components - experience:naming - experience:consistency limit-path-length: message: APIs SHOULD NOT expand their total URL length beyond a few hundred characters. severity: warn given: $.paths.*~ then: function: length functionOptions: max: 100 tags: - source:sps-commerce - format:openapi - spec:paths - experience:usability - experience:consistency description: "APIs SHOULD NOT expand their total URL length beyond a few hundred characters. It constrains the length of the targeted value and at most 100 (evaluated at `$.paths.*~`). Severity: warn." servers-must-use-https: message: Servers MUST be https and no other protocol is allowed unless using localhost. formats: - oas3 severity: error given: $.servers..url then: function: pattern functionOptions: match: ^(https:|http://localhost) tags: - source:sps-commerce - format:openapi - spec:servers - experience:security - experience:reliability description: "Servers MUST be https and no other protocol is allowed unless using localhost. It requires the targeted value to match the pattern `^(https:|http://localhost)` (evaluated at `$.servers..url`). Severity: error." server-url-must-be-lowercase: message: Server URL SHOULD BE lowercase. formats: - oas3 severity: warn given: $.servers..url then: function: pattern functionOptions: match: ^[^A-Z]*$ tags: - source:sps-commerce - format:openapi - spec:servers - experience:naming - experience:consistency description: "Server URL SHOULD BE lowercase. It requires the targeted value to match the pattern `^[^A-Z]*$` (evaluated at `$.servers..url`). Severity: warn." servers-on-approved-domain: message: APIs SHOULD be accessible under api.spscommerce.com. formats: - oas3 severity: warn given: $.servers..url then: function: pattern functionOptions: match: api.spscommerce.com|api.sps-internal.com|localhost tags: - source:sps-commerce - format:openapi - spec:servers - experience:governance - experience:consistency description: "APIs SHOULD be accessible under api.spscommerce.com. It requires the targeted value to match the pattern `api.spscommerce.com|api.sps-internal.com|localhost` (evaluated at `$.servers..url`). Severity: warn." no-environment-names-in-paths: message: API paths MUST NOT indicate environment names. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: /prod/|/preprod/|/dev/|/test/|/integration/|/stage/ tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:governance description: "API paths MUST NOT indicate environment names. It requires the targeted value not to match `/prod/|/preprod/|/dev/|/test/|/integration/|/stage/` (evaluated at `$.paths.*~`). Severity: error." servers-must-not-specify-port: message: Port MUST NOT be specified or required to use the API, except for 'localhost' testing in a spec. formats: - oas3 severity: error given: $.servers..url then: function: pattern functionOptions: notMatch: (?!https?://localhost)(https?://.*):(\d*)\/?(.*) tags: - source:sps-commerce - format:openapi - spec:servers - experience:usability - experience:consistency description: "Port MUST NOT be specified or required to use the API, except for 'localhost' testing in a spec. It requires the targeted value not to match `(?!https?://localhost)(https?://.*):(\\d*)\\/?(.*)` (evaluated at `$.servers..url`). Severity: error." no-technology-leak-in-paths: message: A resource MUST NOT leak or expose format or technology-specific information at any point in the path. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: (.php|.asp|.jsp|.cgi|.psp|.json|.xml) tags: - source:sps-commerce - format:openapi - spec:paths - experience:security - experience:naming description: "A resource MUST NOT leak or expose format or technology-specific information at any point in the path. It requires the targeted value not to match `(.php|.asp|.jsp|.cgi|.psp|.json|.xml)` (evaluated at `$.paths.*~`). Severity: error." no-file-extension-in-paths: message: A resource SHOULD NOT make use of an extension at any point in the path. severity: warn given: $.paths.*~ then: function: pattern functionOptions: notMatch: \. tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency description: "A resource SHOULD NOT make use of an extension at any point in the path. It requires the targeted value not to match `\\.` (evaluated at `$.paths.*~`). Severity: warn." path-segments-kebab-case-3: message: A resource containing multiple words MUST be separated using kebab-case (lower case and separated with hyphens). severity: error given: $.paths[?(/^((?!_webhooks).)*$/i.test(@property))]~ then: function: pattern functionOptions: notMatch: (\/[a-z]+_.)|(\/([a-z]|[A-Z])+[A-Z]) tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency description: "A resource containing multiple words MUST be separated using kebab-case (lower case and separated with hyphens). It requires the targeted value not to match `(\\/[a-z]+_.)|(\\/([a-z]|[A-Z])+[A-Z])` (evaluated at `$.paths[?(/^((?!_webhooks).)*$/i.test(@property))]~`). Severity: error." no-trailing-slash-in-paths: message: A resource MUST be addressable without a trailing slash on the path. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: /$ tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency - source:api-evangelist description: "A resource MUST be addressable without a trailing slash on the path. It requires the targeted value not to match `/$` (evaluated at `$.paths.*~`). Severity: error." no-api-prefix-in-paths: message: A resource SHOULD NOT contain 'api' as a prefix in or a part of the path. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: /api|/api/|-api/ tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency description: "A resource SHOULD NOT contain 'api' as a prefix in or a part of the path. It requires the targeted value not to match `/api|/api/|-api/` (evaluated at `$.paths.*~`). Severity: error." no-empty-path-segments: message: A resource MUST use normalized paths without empty path segments. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: // tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency description: "A resource MUST use normalized paths without empty path segments. It requires the targeted value not to match `//` (evaluated at `$.paths.*~`). Severity: error." limit-path-parameters: message: The URL path should not contain more than 3 dynamic path parameters. severity: warn given: $.paths.*~ then: function: pattern functionOptions: notMatch: ^(.*{{1}.*){4,} tags: - source:sps-commerce - format:openapi - spec:paths - experience:usability - experience:consistency description: "The URL path should not contain more than 3 dynamic path parameters. It requires the targeted value not to match `^(.*{{1}.*){4,}` (evaluated at `$.paths.*~`). Severity: warn." limit-nested-sub-resources: message: The hierarchy of nested resources SHOULD NOT contain more than 8 resource names in the path. severity: warn given: $.paths.*~ then: function: pattern functionOptions: notMatch: ^([^/]*/){9,} tags: - source:sps-commerce - format:openapi - spec:paths - experience:usability - experience:consistency description: "The hierarchy of nested resources SHOULD NOT contain more than 8 resource names in the path. It requires the targeted value not to match `^([^/]*/){9,}` (evaluated at `$.paths.*~`). Severity: warn." no-http-methods-in-paths: message: A resource SHOULD NOT contain HTTP methods. severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: (\/get|\/post|\/put|\/delete|\/patch) tags: - source:sps-commerce - format:openapi - spec:paths - experience:naming - experience:consistency description: "A resource SHOULD NOT contain HTTP methods. It requires the targeted value not to match `(\\/get|\\/post|\\/put|\\/delete|\\/patch)` (evaluated at `$.paths.*~`). Severity: error." path-parameters-camel-case-2: message: Path parameter keys MUST use camelCase. severity: error given: $.paths.*.*.parameters[?(@.in=='path')].name then: function: casing functionOptions: type: camel disallowDigits: true tags: - source:sps-commerce - format:openapi - spec:paths - spec:parameters - experience:naming - experience:consistency description: "Path parameter keys MUST use camelCase. It requires camel casing on the targeted value (evaluated at `$.paths.*.*.parameters[?(@.in=='path')].name`). Severity: error." query-parameter-allowed-characters: message: "Query parameter keys MUST include only alpha-numeric characters and periods: [Aa0-Zz9]'." severity: error given: $.paths.*.*.parameters[?(@.in=='query')].name then: function: pattern functionOptions: match: ^[A-Za-z0-9\.]+$ tags: - source:sps-commerce - format:openapi - spec:paths - spec:parameters - experience:naming - experience:consistency description: "Query parameter keys MUST include only alpha-numeric characters and periods: [Aa0-Zz9]'. It requires the targeted value to match the pattern `^[A-Za-z0-9\\.]+$` (evaluated at `$.paths.*.*.parameters[?(@.in=='query')].name`). Severity: error." query-parameters-camel-case-2: message: Query parameter keys MUST use camelCase. severity: error given: $.paths.*.*.parameters[?(@.in=='query')].name then: function: casing functionOptions: type: camel disallowDigits: true separator: char: . allowLeading: false tags: - source:sps-commerce - format:openapi - spec:paths - spec:parameters - experience:naming - experience:consistency description: "Query parameter keys MUST use camelCase. It requires camel casing on the targeted value (evaluated at `$.paths.*.*.parameters[?(@.in=='query')].name`). Severity: error." query-parameters-must-be-optional: message: Query parameters MUST be optional. severity: error given: $.paths.*.*.parameters[?(@.in=='query')].required then: function: falsy tags: - source:sps-commerce - format:openapi - spec:paths - spec:parameters - experience:usability - experience:consistency description: "Query parameters MUST be optional. It requires the targeted value to be absent or empty (evaluated at `$.paths.*.*.parameters[?(@.in=='query')].required`). Severity: error." no-api-keys-in-query-parameters: message: Query parameters MUST not contain sensitive information, like API tokens or keys. severity: error given: $.paths.*.*.parameters[?(@.in=='query')].name then: function: pattern functionOptions: notMatch: apiKey|token tags: - source:sps-commerce - format:openapi - spec:paths - spec:parameters - experience:security - experience:governance description: "Query parameters MUST not contain sensitive information, like API tokens or keys. It requires the targeted value not to match `apiKey|token` (evaluated at `$.paths.*.*.parameters[?(@.in=='query')].name`). Severity: error." no-query-strings-in-paths: message: Paths SHOULD NOT have query parameters in them. They should be defined separately in the OpenAPI. severity: warn given: $.paths.*~ then: function: pattern functionOptions: notMatch: \? tags: - source:sps-commerce - format:openapi - spec:paths - experience:consistency - experience:naming description: "Paths SHOULD NOT have query parameters in them. They should be defined separately in the OpenAPI. It requires the targeted value not to match `\\?` (evaluated at `$.paths.*~`). Severity: warn." response-must-use-json-content-type: description: "API responses should use application/json as the primary content type. Analysis of 773 specs shows application/json is used by 92% of APIs, making it the universal standard for modern REST APIs. It requires the `application/json` field to be present and non-empty (evaluated at `$.paths.*[get,post,put,patch,delete].responses[*].content`). Severity: error." message: Response MUST Use application/json Content Type severity: error given: $.paths.*[get,post,put,patch,delete].responses[*].content then: field: application/json function: truthy tags: - source:api-evangelist - format:openapi - spec:paths - spec:operations - spec:responses - spec:media-types - experience:consistency - experience:usability request-body-must-use-json-content-type: description: "Request bodies should use application/json as the primary content type for consistency across API operations and client implementations. It requires the `application/json` field to be present and non-empty (evaluated at `$.paths.*[post,put,patch].requestBody.content`). Severity: error." message: Request Body MUST Use application/json Content Type severity: error given: $.paths.*[post,put,patch].requestBody.content then: field: application/json function: truthy tags: - source:api-evangelist - format:openapi - spec:paths - spec:operations - spec:request-body - spec:media-types - experience:consistency - experience:usability info-description-no-eval-tag: description: "Eval functions MUST not be included in the description of an API, keeping descriptions to just the text that is needed, and relying on the rest of the OpenAPI to describe what is possible. It requires the `description` field not to match `^\\b(