# harvested from https://github.com/Logius-standaarden/Publicatie-Preview/blob/69a551bca14beeea84213c155a7c82c75bafabe5/API-Design-Rules/release/2.2/media/linter.yaml on 2026-10-09 — a Spectral ruleset published in the provider's own GitHub repository (Logius-standaarden/Publicatie-Preview); found by GitHub code search, fetched verbatim x-method: harvested x-stamped: 2026-10-09 x-source-url: https://github.com/Logius-standaarden/Publicatie-Preview/blob/69a551bca14beeea84213c155a7c82c75bafabe5/API-Design-Rules/release/2.2/media/linter.yaml # Deze linter configuratie is geschreven voor Spectral. Voor meer informatie over # die tool, zie https://stoplight.io/open-source/spectral # # De linter configuratie wordt tevens gehost op https://developer.overheid.nl (DON). # Deze kan worden gebruikt in onder andere CI systemen voor live updates van de # configuratie. # # Voor meer informatie hierover, zie de kennisbank van DON: # https://developer.overheid.nl/kennisbank/apis/api-design-rules/api-design-rules-linter # # Hierbij ook de ingevoegde instructies die kunnen worden gekopieerd om de linter # te draaien: # # ``` # npm install -g @stoplight/spectral-cli # curl -L https://static.developer.overheid.nl/adr/ruleset.yaml > .linter.yaml # spectral lint -r .linter.yaml $OAS_URL_OR_FILE # ``` extends: - ["spectral:oas", "off"] # extend spectral:oas maar zet standaard alle regels uit rules: #/core/publish-openapi (deze error-rules valideren of OAS valid is) oas3-schema: error operation-operationId-unique: error path-params: error openapi-tags-uniqueness: error oas3-valid-media-example: error oas3-valid-schema-example: error oas3-server-variables: error oas3-api-servers: error #/core/no-trailing-slash path-keys-no-trailing-slash: error #/core/doc-openapi nlgov:openapi3: severity: error given: $.['openapi'] then: function: pattern functionOptions: match: '^3(.\d+){1,2}$' message: "The OpenAPI Specification is versioned using a `major.minor.patch` versioning scheme. Use a version 3 OpenAPI Specification for documentation." nlgov:openapi-root-exists: severity: error given: $ then: field: openapi function: truthy message: "The root of the document must contain the `openapi` property." #/core/version-header nlgov:missing-version-header: severity: error given: $..[responses][?(@property && @property.match(/(2|3)\d\d/))][headers] then: function: or functionOptions: properties: - API-Version - Api-Version - Api-version - api-version - API-version message: "Return the full version number in a response header." documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/version-header" nlgov:missing-header: severity: error given: $..[responses][?(@property && @property.match(/(2|3)\d\d/))] then: field: headers function: truthy message: "Return the full version number in a response header." documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/version-header" #/core/uri-version nlgov:include-major-version-in-uri: severity: error given: - "$.servers[*]" then: function: pattern functionOptions: match: "\\/v[\\d+]" field: url message: "Include the major version number in the URI." documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/uri-version" #/core/no-trailing-slash nlgov:paths-no-trailing-slash: severity: error given: - "$.paths" then: function: pattern functionOptions: notMatch: ".+ \\/$" field: "@key" message: "Leave off trailing slashes from URIs." documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/no-trailing-slash" #/core/doc-openapi-contact info-contact: severity: error given: - "$" then: field: "info.contact" function: truthy message: 'Info object must have "contact" object.' documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/doc-openapi-contact" nlgov:info-contact-fields-exist: severity: error given: - "$.info.contact" then: function: schema functionOptions: schema: required: - email - name - url message: "Missing fields in `info.contact` field. Must specify email, name and url." documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/doc-openapi-contact" #/core/http-methods nlgov:http-methods: severity: error given: - "$.paths[?(@property && @property.match(/(description|summary)/i))]" then: function: pattern functionOptions: match: "post|put|get|delete|patch|parameters" field: "@key" message: "Only apply standard HTTP methods." documentationUrl: "https://developer.overheid.nl/kennisbank/apis/api-design-rules/hoe-te-voldoen/http-methods" #/core/path-segments-kebab-case nlgov:paths-kebab-case: severity: error message: "{{property}} is not kebab-case." given: $.paths[?(@property && !@property.match(/\/openapi\.(json)|(yaml)/))]~ then: function: pattern functionOptions: # Deze regex bestaat uit meerdere delen. Ter toelichting: # - `\/` staat toe dat een pad enkel een `/` is (de landingspagina) # - `\/_[a-z0-9]+` staat toe dat het laatste stuk van een pad mag beginnen met een `_` # - ([a-z0-9\-]+|{[^}]+}) zijn kebab-case paden of met variabele notatie (`{id}`) # - Paden mogen nesten, waardoor de twee groep genest wordt, gescheiden met een `/` # - Een pad mag eindigen met een `/`. Dat is volgens een andere regel niet toegestaan, maar we willen niet twee errors genereren match: ^(\/|(\/_[a-z0-9]+|\/(([a-z0-9\-]+|{[^}]+})(\/([a-z0-9\-\.]+|{[^}]+}))*)(\/_[a-z]+)?)\/?)$ #/core/query-keys-camel-case nlgov:query-keys-camel-case: severity: error message: "{{value}} is not lower camelCase." given: - $.paths.*.*.parameters[?(@.in=='query')] - $.components.securitySchemes[?(@.in=='query')] then: function: pattern field: name functionOptions: match: ^\$?[a-z][a-z\d]*([A-Z][a-z\d]*)*$ nlgov:schema-camel-case: severity: warn message: "Schema name should be UpperCamelCase in {{path}}" given: >- $.components.schemas[*]~ then: function: casing functionOptions: type: pascal separator: char: "" nlgov:servers-use-https: severity: warn message: "Server URL {{value}} {{error}}." given: - $.servers[*] - $.paths..servers[*] then: field: url function: pattern functionOptions: match: ^https://.* #/core/error-handling/problem-details nlgov:use-problem-schema: severity: error message: "The content type of an error response should be application/problem+json or application/problem+xml to match RFC 9457." given: $..[responses][?(@property && @property.match(/(4|5)\d\d/))].content then: function: schema functionOptions: schema: anyOf: - required: ["application/problem+json"] - required: ["application/problem+xml"] nlgov:problem-schema-members: severity: error message: "{{error}}. These fields are required: status, title and detail." given: $..[responses][?(@property && @property.match(/(4|5)\d\d/))].content[?(@property=="application/problem+json" || @property=="application/problem+xml")]..schema then: function: schema functionOptions: schema: type: object properties: properties: type: object required: - status - title - detail #/core/error-handling/invalid-input nlgov:problem-invalid-input: severity: error message: "GET and DELETE endpoints that have parameters, and all other endpoints must be able to return a 400 response" given: - $.paths..[?( @property.match(/(get)|(delete)/) && @.parameters && @.parameters.length > 0 )] - $.paths..[?( @property.match(/(put)|(post)|(patch)/))] then: function: schema functionOptions: schema: type: object properties: responses: type: object required: - "400" nlgov:property-casing: severity: warn given: - "$.*.schemas[*].properties.[?(@property && @property.match(/_links/i))]" then: function: casing functionOptions: type: camel field: "@key" message: Properties must be lowerCamelCase. #/core/date-time/timezone nlgov:date-time-ensure-timezone: severity: error given: $..properties[*].format message: "Use date-time format which includes a timezone" then: function: pattern functionOptions: notMatch: "/^date-time-local$/" nlgov:time-without-timezone: severity: error given: $..properties[*].format message: "Use time-local format without a timezone" then: function: pattern functionOptions: notMatch: "/^time$/" #/core/date-time/date-omit-time-portion nlgov:specify-format-for-date-and-time: severity: error given: - $..properties[date,datum] - $..properties[?(@property && @property.match(/((\w+D)|(_[dD]))((ate)|(atum))/))] message: "Any date field must set 'format' to 'date'" then: function: schema functionOptions: schema: anyOf: - required: ["format"] - properties: allOf: type: array items: required: ["format"] required: ["allOf"] nlgov:use-date-instead-of-datetime: severity: error given: - $..properties[date,datum]..format - $..properties[?(@property && @property.match(/((\w+D)|(_[dD]))((ate)|(atum))/))]..format message: "Field represents a date and therefore must set 'format' to 'date'" then: function: pattern functionOptions: notMatch: "/^date-time$/" nlgov:semver: severity: error message: "Version {{value}} is not in semver format." given: $.info.version then: function: pattern functionOptions: match: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$