# Spectral ruleset for Grubhub Partner Integration APIs # Generated by the API Evangelist profiling pipeline. # Enforces the conventions observed across the Grubhub OpenAPI specifications: # - OpenAPI 3.1.0 # - /pos/v1/ path prefix with snake_case path/query parameters # - snake_case schema properties # - camelCase operationIds with verb prefixes (get/list/create/update/confirm/...) # - Title Case tags # - "Grubhub " prefixed operation summaries # - HMAC (Authorization header + X-GH-PARTNER-KEY) and OAuth bearer security # - { error, message, status } error envelope extends: [] rules: # ---------------------------------------------------------------------- # INFO / METADATA # ---------------------------------------------------------------------- info-title-grubhub-prefix: description: API title should start with "Grubhub". severity: warn given: $.info.title then: function: pattern functionOptions: match: '^Grubhub' info-description-required: description: Info object must have a non-trivial description. severity: warn given: $.info then: field: description function: truthy info-description-min-length: description: Info description should be reasonably descriptive. severity: info given: $.info.description then: function: length functionOptions: min: 40 info-version-required: description: API version must be defined. severity: error given: $.info then: field: version function: truthy info-contact-required: description: A contact object should be present. severity: info given: $.info then: field: contact function: truthy info-terms-of-service: description: Terms of service should be linked. severity: info given: $.info then: field: termsOfService function: truthy # ---------------------------------------------------------------------- # OPENAPI VERSION # ---------------------------------------------------------------------- openapi-version-3-1: description: Grubhub specs use OpenAPI 3.1.0. severity: warn given: $.openapi then: function: pattern functionOptions: match: '^3\.1\.' # ---------------------------------------------------------------------- # SERVERS # ---------------------------------------------------------------------- servers-defined: description: At least one server must be defined. severity: error given: $.servers then: function: truthy servers-https-only: description: Server URLs must use HTTPS. severity: error given: $.servers[*].url then: function: pattern functionOptions: match: '^https://' servers-description: description: Each server should have a description. severity: info given: $.servers[*] then: field: description function: truthy # ---------------------------------------------------------------------- # PATHS — NAMING CONVENTIONS # ---------------------------------------------------------------------- paths-pos-v1-prefix: description: Grubhub partner paths are namespaced under /pos/v1/. severity: warn given: $.paths[*]~ then: function: pattern functionOptions: match: '^/pos/v1/' paths-no-trailing-slash: description: Paths must not end with a trailing slash. severity: warn given: $.paths[*]~ then: function: pattern functionOptions: notMatch: '.+/$' paths-snake-case-params: description: Path templating uses snake_case parameter names. severity: warn given: $.paths[*]~ then: function: pattern functionOptions: notMatch: '\{[a-z]+[A-Z]' # ---------------------------------------------------------------------- # OPERATIONS # ---------------------------------------------------------------------- operation-summary-required: description: Every operation must have a summary. severity: error given: $.paths[*][get,post,put,patch,delete] then: field: summary function: truthy operation-summary-grubhub-prefix: description: Operation summaries should start with "Grubhub". severity: warn given: $.paths[*][get,post,put,patch,delete].summary then: function: pattern functionOptions: match: '^Grubhub ' operation-description-required: description: Every operation must have a description. severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: description function: truthy operation-operationid-required: description: Every operation must have an operationId. severity: error given: $.paths[*][get,post,put,patch,delete] then: field: operationId function: truthy operation-operationid-camelcase: description: operationId must be camelCase. severity: warn given: $.paths[*][get,post,put,patch,delete].operationId then: function: casing functionOptions: type: camel operation-operationid-verb-prefix: description: operationId should start with a recognized verb prefix. severity: info given: $.paths[*][get,post,put,patch,delete].operationId then: function: pattern functionOptions: match: '^(get|list|create|update|delete|confirm|poll|ingest|retrieve|report|activate|deactivate|associate|cancel)' operation-tags-required: description: Every operation must be tagged. severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: tags function: truthy operation-microcks-extension: description: Operations should carry an x-microcks-operation extension for mock compatibility. severity: info given: $.paths[*][get,post,put,patch,delete] then: field: x-microcks-operation function: truthy # ---------------------------------------------------------------------- # TAGS # ---------------------------------------------------------------------- tags-global-defined: description: Global tags array should be defined. severity: info given: $ then: field: tags function: truthy tag-description-required: description: Each global tag should have a description. severity: info given: $.tags[*] then: field: description function: truthy tag-title-case: description: Tag names use Title Case (each word capitalized). severity: warn given: $.tags[*].name then: function: pattern functionOptions: match: '^[A-Z][A-Za-z]*( [A-Z][A-Za-z]*)*$' # ---------------------------------------------------------------------- # PARAMETERS # ---------------------------------------------------------------------- parameter-description-required: description: Parameters must have a description. severity: warn given: $.paths[*][*].parameters[*] then: field: description function: truthy parameter-snake-case: description: Parameter names use snake_case. severity: warn given: $.paths[*][*].parameters[?(@.name)].name then: function: pattern functionOptions: match: '^[a-z][a-z0-9_]*$' parameter-schema-typed: description: Parameters must declare a schema type. severity: warn given: $.paths[*][*].parameters[*].schema then: field: type function: truthy parameter-component-description: description: Shared parameter components must have a description. severity: warn given: $.components.parameters[*] then: field: description function: truthy # ---------------------------------------------------------------------- # REQUEST BODIES # ---------------------------------------------------------------------- request-body-json: description: Request bodies should offer application/json content. severity: warn given: $.paths[*][post,put,patch].requestBody.content then: field: application/json function: truthy # ---------------------------------------------------------------------- # RESPONSES # ---------------------------------------------------------------------- response-success-defined: description: Each operation must define a 2xx success response. severity: error given: $.paths[*][get,post,put,patch,delete].responses then: function: schema functionOptions: schema: type: object anyOf: - required: ['200'] - required: ['201'] - required: ['202'] - required: ['204'] response-auth-failure-defined: description: Operations should document a 401 authentication-failure response. severity: info given: $.paths[*][get,post,put,patch,delete].responses then: field: '401' function: truthy response-description-required: description: Each response must have a description. severity: warn given: $.paths[*][*].responses[*] then: field: description function: truthy # ---------------------------------------------------------------------- # SCHEMAS — PROPERTY NAMING # ---------------------------------------------------------------------- schema-property-snake-case: description: Schema properties use snake_case. severity: warn given: $.components.schemas[*].properties[*]~ then: function: pattern functionOptions: match: '^[a-z][a-z0-9_]*$' schema-description-required: description: Top-level component schemas must have a description. severity: warn given: $.components.schemas[*] then: field: description function: truthy schema-property-typed: description: Schema properties must declare a type or $ref. severity: warn given: $.components.schemas[*].properties[*] then: function: schema functionOptions: schema: type: object anyOf: - required: ['type'] - required: ['$ref'] - required: ['allOf'] - required: ['oneOf'] schema-error-envelope: description: The Error schema should expose error, message, and status fields. severity: info given: $.components.schemas.Error.properties then: function: schema functionOptions: schema: type: object required: ['error', 'message', 'status'] # ---------------------------------------------------------------------- # SECURITY # ---------------------------------------------------------------------- security-global-defined: description: A global security requirement should be declared. severity: warn given: $ then: field: security function: truthy security-schemes-defined: description: Security schemes must be defined under components. severity: error given: $.components then: field: securitySchemes function: truthy security-scheme-description: description: Each security scheme should be described. severity: info given: $.components.securitySchemes[*] then: field: description function: truthy security-hmac-authorization-header: description: HMAC scheme should be carried in the Authorization header. severity: info given: $.components.securitySchemes.hmacAuth then: field: name function: pattern functionOptions: match: '^Authorization$' # ---------------------------------------------------------------------- # 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 # ---------------------------------------------------------------------- # GENERAL QUALITY # ---------------------------------------------------------------------- external-docs-encouraged: description: Specs are encouraged to link external documentation. severity: info given: $ then: field: externalDocs function: truthy operation-examples-encouraged: description: JSON responses are encouraged to provide examples for mocking. severity: info given: $.paths[*][*].responses[*].content.application/json then: function: schema functionOptions: schema: type: object anyOf: - required: ['example'] - required: ['examples']