# Flipdish API Spectral Ruleset # Generated by the API Evangelist pipeline from the Flipdish Open API v1.0 specifications. # Aligned with Flipdish's own published API Design Guide ruleset # (github.com/flipdishbytes/spectral-rules): camelCase paths, production-only servers, # required summaries/descriptions, error object validation, approved status codes. extends: ["spectral:oas"] rules: # ─────────────────────────── INFO / METADATA ─────────────────────────── info-title-flipdish-prefix: description: "API title should start with 'Flipdish'." severity: warn given: "$.info.title" then: function: pattern functionOptions: match: "^Flipdish" info-description-required: description: "The info block must have a description." severity: warn given: "$.info" then: field: description function: truthy info-version-required: description: "The info block must declare a version." severity: error given: "$.info" then: field: version function: truthy info-contact-email-flipdish: description: "Contact email must be help@flipdish.com (per Flipdish API Design Guide)." severity: warn given: "$.info.contact.email" then: function: pattern functionOptions: match: "^help@flipdish\\.com$" # ─────────────────────────── OPENAPI VERSION ─────────────────────────── openapi-version-3: description: "Specs must be OpenAPI 3.0.x." severity: error given: "$.openapi" then: function: pattern functionOptions: match: "^3\\.0\\." # ─────────────────────────── SERVERS ─────────────────────────── servers-defined: description: "A servers array must be defined." severity: error given: "$" then: field: servers function: truthy servers-flipdish-production-only: description: "Only Flipdish production domains (https://api.flipdish.co) are allowed as server URLs." severity: error given: "$.servers[*].url" then: function: pattern functionOptions: match: "^https://api\\.flipdish\\.co($|/)" # ─────────────────────────── PATHS — NAMING ─────────────────────────── paths-no-trailing-slash: description: "Paths should not end with a trailing slash." severity: warn given: "$.paths" then: field: "@key" function: pattern functionOptions: notMatch: ".+/$" paths-lower-camel-segments: description: "Path segments should be lowerCamelCase (Flipdish convention), parameters in {braces}." severity: warn given: "$.paths" then: field: "@key" function: pattern functionOptions: match: "^(/(\\{[a-zA-Z0-9_]+\\}|[a-z][a-zA-Z0-9.]*))+$" # ─────────────────────────── OPERATIONS ─────────────────────────── operation-summary-required: description: "Every operation must have a summary (Flipdish API Design Guide)." severity: error given: "$.paths[*][get,post,put,delete,patch]" then: field: summary function: truthy operation-summary-flipdish-prefix: description: "Operation summaries should begin with 'Flipdish'." severity: info given: "$.paths[*][get,post,put,delete,patch].summary" then: function: pattern functionOptions: match: "^Flipdish" operation-description-required: description: "Every operation must have a description (Flipdish API Design Guide)." severity: error given: "$.paths[*][get,post,put,delete,patch]" then: field: description function: truthy operation-operationid-required: description: "Every operation must declare an operationId." severity: error given: "$.paths[*][get,post,put,delete,patch]" then: field: operationId function: truthy operation-operationid-pascal-case: description: "operationId uses PascalCase (Flipdish convention, e.g. GetAccountDetails)." severity: info given: "$.paths[*][get,post,put,delete,patch].operationId" then: function: pattern functionOptions: match: "^[A-Z][A-Za-z0-9]+$" operation-tags-required: description: "Every operation must be tagged." severity: warn given: "$.paths[*][get,post,put,delete,patch]" then: field: tags function: truthy # ─────────────────────────── TAGS ─────────────────────────── tag-description-required: description: "Global tags should have descriptions." severity: info given: "$.tags[*]" then: field: description function: truthy tags-pascal-case: description: "Tags use PascalCase resource names (Flipdish convention, e.g. Stores, MenuSections)." severity: info given: "$.tags[*].name" then: function: pattern functionOptions: match: "^[A-Z][A-Za-z0-9]+$" # ─────────────────────────── PARAMETERS ─────────────────────────── parameter-description-required: description: "Parameters must have descriptions." severity: warn given: "$.paths[*][*].parameters[*]" then: field: description function: truthy parameter-schema-required: description: "Parameters must declare a schema with a type." severity: warn given: "$.paths[*][*].parameters[?(@.in)]" then: field: schema function: truthy # ─────────────────────────── REQUEST BODIES ─────────────────────────── request-body-json: description: "Request bodies should offer application/json content." severity: info given: "$.paths[*][post,put,patch].requestBody.content" then: field: "application/json" function: truthy # ─────────────────────────── RESPONSES ─────────────────────────── response-approved-status-codes: description: "Only Flipdish-approved status codes may be used." severity: error given: "$.paths[*][*].responses.*~" then: function: enumeration functionOptions: values: ["200","201","204","400","401","403","404","409","414","429","500","default"] response-unauthorized-defined: description: "Operations should document a 401 Unauthorized response." severity: info given: "$.paths[*][get,post,put,delete,patch].responses" then: field: "401" function: truthy response-error-object: description: "4xx/5xx JSON responses must include an 'error' object (Flipdish error format)." severity: warn given: "$.paths[*][*].responses[400,401,403,404,409,414,429,500].content[application/json].schema" then: function: truthy # ─────────────────────────── SECURITY ─────────────────────────── global-security-defined: description: "A global security requirement must be defined (OAuth 2.0)." severity: warn given: "$" then: field: security function: truthy security-scheme-oauth2: description: "The oauth2 security scheme must be defined in components." severity: error given: "$.components.securitySchemes" then: field: oauth2 function: truthy # ─────────────────────────── SCHEMAS ─────────────────────────── schema-properties-typed: description: "Schema properties should declare a type, $ref, or composition keyword." severity: info given: "$.components.schemas[*].properties[*]" then: function: schema functionOptions: schema: anyOf: - required: ["type"] - required: ["$ref"] - required: ["allOf"] - required: ["oneOf"] - required: ["anyOf"] # ─────────────────────────── HTTP METHOD CONVENTIONS ─────────────────────────── get-no-request-body: description: "GET operations must not declare a request body." severity: error given: "$.paths[*].get" then: field: requestBody function: falsy delete-no-request-body: description: "DELETE operations should not declare a request body." severity: warn given: "$.paths[*].delete" then: field: requestBody function: falsy