Programming Quotes · API Governance Rules

Programming Quotes API Rules

Spectral linting rules defining API design standards and conventions for Programming Quotes.

42 Rules error 15 warn 24 info 3
Authorship not recorded No authorship marker is recorded for this file. It is not presented as the provider's; it was most likely written by an API Evangelist pass before outputs were stamped.
View Rules File View on GitHub

Rule Categories

http info microcks no openapi operation parameter paths request response schema security servers tags

Rules

warn
info-title-format
Info title must start with "Programming Quotes".
$.info.title
warn
info-description-min-length
Info description must be at least 50 characters.
$.info.description
warn
info-contact-required
Info contact block is required.
$.info
warn
info-license-required
Info license block is required (community license is fine).
$.info
error
openapi-version-3-0-x
Must use OpenAPI 3.0.x.
$.openapi
error
servers-defined
At least one server must be declared.
$
error
servers-https-only
All server URLs must be HTTPS.
$.servers[*].url
warn
servers-description-required
Each server must have a description.
$.servers[*]
warn
paths-kebab-case
Path segments must be kebab-case (lowercase, hyphens). Path params allowed.
$.paths[*]~
error
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths[*]~
error
paths-no-query-strings
Paths must not contain query strings.
$.paths[*]~
error
operation-summary-required
Every operation must have a summary.
$.paths[*][get,post,put,patch,delete]
warn
operation-description-required
Every operation must have a description.
$.paths[*][get,post,put,patch,delete]
warn
operation-summary-provider-prefix
Operation summaries should start with "Programming Quotes".
$.paths[*][get,post,put,patch,delete].summary
error
operation-operationid-required
Every operation must have an operationId.
$.paths[*][get,post,put,patch,delete]
warn
operation-operationid-camel-case
operationIds must be camelCase.
$.paths[*][get,post,put,patch,delete].operationId
info
operation-operationid-verb-prefix
operationIds should start with a known verb (get, list, create, update, delete, add, vote, issue).
$.paths[*][get,post,put,patch,delete].operationId
error
operation-tags-required
Every operation must have at least one tag.
$.paths[*][get,post,put,patch,delete]
warn
tags-global-defined
Global tags array must be defined.
$
warn
tags-title-case
Tag names must be Title Case single words (e.g., Quotes, Authentication).
$.tags[*].name
warn
tags-description-required
Each global tag must have a description.
$.tags[*]
warn
parameter-description-required
Every parameter must have a description.
$.paths[*][get,post,put,patch,delete].parameters[*]
warn
parameter-query-camel-case
Query parameters must be camelCase (matches `quotesPerPage`, `author`, `page`).
$.paths[*][get,post,put,patch,delete].parameters[?(@.in == 'query')].name
error
parameter-schema-required
Every parameter must have a schema with a type.
$.paths[*][get,post,put,patch,delete].parameters[*]
error
request-body-json-content-type
Request bodies must offer application/json.
$.paths[*][post,put,patch].requestBody.content
warn
request-body-description-required
Request bodies should have a description.
$.paths[*][post,put,patch].requestBody
error
response-success-required
Every operation must define at least one 2xx response.
$.paths[*][get,post,put,patch,delete].responses
warn
response-401-on-writes
Write operations should document a 401 response.
$.paths[*][post,put,patch,delete].responses
warn
response-404-on-by-id
Operations on /quotes/{id} should document a 404.
$.paths[?(@property.match(/\{id\}/))][get,put,patch,delete].responses
error
response-description-required
Every response must have a description.
$.paths[*][get,post,put,patch,delete].responses[*]
warn
response-json-content-type
2xx and 4xx responses should use application/json (204 may omit content).
$.paths[*][get,post,put,patch,delete].responses[?(@property.match(/^(2[0-35-9][0-9]|4[0-9]{2})$/))].content
warn
response-error-schema-has-message
Error response schemas should expose a `message` field.
$.components.schemas.ErrorResponse.properties
warn
schema-property-camel-case
Schema properties must be camelCase (allow MongoDB `_id`).
$.components.schemas[*].properties[*]~
warn
schema-top-level-description
Top-level schemas must have a description.
$.components.schemas[*]
error
schema-top-level-type
Top-level schemas must have a type.
$.components.schemas[*]
error
security-scheme-defined
A bearerAuth security scheme must be defined.
$.components.securitySchemes
warn
security-bearer-jwt
bearerAuth must declare bearerFormat=JWT.
$.components.securitySchemes.bearerAuth
warn
security-write-operations-protected
Write operations (POST/PUT/DELETE on /quotes**) must declare security.
$.paths[?(@property.match(/^\/quotes/))][post,put,delete]
error
http-get-no-request-body
GET operations must not declare a request body.
$.paths[*].get
info
http-delete-204
DELETE operations should document a 204 No Content response.
$.paths[*].delete.responses
warn
no-empty-descriptions
Descriptions must not be empty strings.
$..description
info
microcks-operation-extension
Each operation should declare x-microcks-operation for mock-server compatibility.
$.paths[*][get,post,put,patch,delete]

Spectral Ruleset

Raw ↑
# Spectral ruleset for the Programming Quotes API
# Generated from /Users/kinlane/GitHub/all/programming-quotes/openapi/programming-quotes-openapi.yml
# Conventions captured:
#   - kebab-case paths, no version prefix on canonical surface (`/api` is server-level)
#   - camelCase query parameters and body property names
#   - camelCase operationIds with verb prefixes (get/list/create/update/delete/issue/add/vote)
#   - Title-Case tags (Quotes, Authors, Authentication)
#   - JWT bearer auth on writes, public on reads
#   - Summaries prefixed with "Programming Quotes"

extends:
  - spectral:oas

rules:

  # ─────────────────────────────────────────────────────────────
  # INFO / METADATA
  # ─────────────────────────────────────────────────────────────
  info-title-format:
    description: Info title must start with "Programming Quotes".
    severity: warn
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        match: '^Programming Quotes'
  info-description-min-length:
    description: Info description must be at least 50 characters.
    severity: warn
    given: $.info.description
    then:
      function: length
      functionOptions:
        min: 50
  info-contact-required:
    description: Info contact block is required.
    severity: warn
    given: $.info
    then:
      field: contact
      function: truthy
  info-license-required:
    description: Info license block is required (community license is fine).
    severity: warn
    given: $.info
    then:
      field: license
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # OPENAPI VERSION
  # ─────────────────────────────────────────────────────────────
  openapi-version-3-0-x:
    description: Must use OpenAPI 3.0.x.
    severity: error
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: '^3\.0\.[0-9]+$'

  # ─────────────────────────────────────────────────────────────
  # SERVERS
  # ─────────────────────────────────────────────────────────────
  servers-defined:
    description: At least one server must be declared.
    severity: error
    given: $
    then:
      field: servers
      function: truthy
  servers-https-only:
    description: All server URLs must be HTTPS.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: '^https://'
  servers-description-required:
    description: Each server must have a description.
    severity: warn
    given: $.servers[*]
    then:
      field: description
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # PATHS — NAMING CONVENTIONS
  # ─────────────────────────────────────────────────────────────
  paths-kebab-case:
    description: Path segments must be kebab-case (lowercase, hyphens). Path params allowed.
    severity: warn
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        match: '^(/([a-z0-9]+(-[a-z0-9]+)*|\{[a-zA-Z][a-zA-Z0-9]*\}))+$'
  paths-no-trailing-slash:
    description: Paths must not end with a trailing slash.
    severity: error
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: '.+/$'
  paths-no-query-strings:
    description: Paths must not contain query strings.
    severity: error
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        notMatch: '\?'

  # ─────────────────────────────────────────────────────────────
  # 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-description-required:
    description: Every operation must have a description.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: description
      function: truthy
  operation-summary-provider-prefix:
    description: Operation summaries should start with "Programming Quotes".
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].summary
    then:
      function: pattern
      functionOptions:
        match: '^Programming Quotes '
  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-camel-case:
    description: operationIds must be camelCase.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].operationId
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'
  operation-operationid-verb-prefix:
    description: operationIds should start with a known verb (get, list, create, update, delete, add, vote, issue).
    severity: info
    given: $.paths[*][get,post,put,patch,delete].operationId
    then:
      function: pattern
      functionOptions:
        match: '^(get|list|create|update|delete|add|vote|issue)[A-Z]'
  operation-tags-required:
    description: Every operation must have at least one tag.
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: tags
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # TAGS
  # ─────────────────────────────────────────────────────────────
  tags-global-defined:
    description: Global tags array must be defined.
    severity: warn
    given: $
    then:
      field: tags
      function: truthy
  tags-title-case:
    description: Tag names must be Title Case single words (e.g., Quotes, Authentication).
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: '^[A-Z][a-zA-Z]+( [A-Z][a-zA-Z]+)*$'
  tags-description-required:
    description: Each global tag must have a description.
    severity: warn
    given: $.tags[*]
    then:
      field: description
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # PARAMETERS
  # ─────────────────────────────────────────────────────────────
  parameter-description-required:
    description: Every parameter must have a description.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].parameters[*]
    then:
      field: description
      function: truthy
  parameter-query-camel-case:
    description: Query parameters must be camelCase (matches `quotesPerPage`, `author`, `page`).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in == 'query')].name
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'
  parameter-schema-required:
    description: Every parameter must have a schema with a type.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].parameters[*]
    then:
      field: schema
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # REQUEST BODIES
  # ─────────────────────────────────────────────────────────────
  request-body-json-content-type:
    description: Request bodies must offer application/json.
    severity: error
    given: $.paths[*][post,put,patch].requestBody.content
    then:
      field: application/json
      function: truthy
  request-body-description-required:
    description: Request bodies should have a description.
    severity: warn
    given: $.paths[*][post,put,patch].requestBody
    then:
      field: description
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # RESPONSES
  # ─────────────────────────────────────────────────────────────
  response-success-required:
    description: Every operation must define at least one 2xx response.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          patternProperties:
            '^2[0-9]{2}$': {}
          minProperties: 1
  response-401-on-writes:
    description: Write operations should document a 401 response.
    severity: warn
    given: $.paths[*][post,put,patch,delete].responses
    then:
      field: '401'
      function: truthy
  response-404-on-by-id:
    description: Operations on /quotes/{id} should document a 404.
    severity: warn
    given: $.paths[?(@property.match(/\{id\}/))][get,put,patch,delete].responses
    then:
      field: '404'
      function: truthy
  response-description-required:
    description: Every response must have a description.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses[*]
    then:
      field: description
      function: truthy
  response-json-content-type:
    description: 2xx and 4xx responses should use application/json (204 may omit content).
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses[?(@property.match(/^(2[0-35-9][0-9]|4[0-9]{2})$/))].content
    then:
      field: application/json
      function: truthy
  response-error-schema-has-message:
    description: Error response schemas should expose a `message` field.
    severity: warn
    given: $.components.schemas.ErrorResponse.properties
    then:
      field: message
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # SCHEMAS — PROPERTY NAMING
  # ─────────────────────────────────────────────────────────────
  schema-property-camel-case:
    description: Schema properties must be camelCase (allow MongoDB `_id`).
    severity: warn
    given: $.components.schemas[*].properties[*]~
    then:
      function: pattern
      functionOptions:
        match: '^(_id|[a-z][a-zA-Z0-9]*)$'
  schema-top-level-description:
    description: Top-level schemas must have a description.
    severity: warn
    given: $.components.schemas[*]
    then:
      field: description
      function: truthy
  schema-top-level-type:
    description: Top-level schemas must have a type.
    severity: error
    given: $.components.schemas[*]
    then:
      field: type
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # SECURITY
  # ─────────────────────────────────────────────────────────────
  security-scheme-defined:
    description: A bearerAuth security scheme must be defined.
    severity: error
    given: $.components.securitySchemes
    then:
      field: bearerAuth
      function: truthy
  security-bearer-jwt:
    description: bearerAuth must declare bearerFormat=JWT.
    severity: warn
    given: $.components.securitySchemes.bearerAuth
    then:
      field: bearerFormat
      function: pattern
      functionOptions:
        match: '^JWT$'
  security-write-operations-protected:
    description: Write operations (POST/PUT/DELETE on /quotes**) must declare security.
    severity: warn
    given: $.paths[?(@property.match(/^\/quotes/))][post,put,delete]
    then:
      field: security
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # HTTP METHOD CONVENTIONS
  # ─────────────────────────────────────────────────────────────
  http-get-no-request-body:
    description: GET operations must not declare a request body.
    severity: error
    given: $.paths[*].get
    then:
      field: requestBody
      function: falsy
  http-delete-204:
    description: DELETE operations should document a 204 No Content response.
    severity: info
    given: $.paths[*].delete.responses
    then:
      field: '204'
      function: truthy

  # ─────────────────────────────────────────────────────────────
  # GENERAL QUALITY
  # ─────────────────────────────────────────────────────────────
  no-empty-descriptions:
    description: Descriptions must not be empty strings.
    severity: warn
    given: $..description
    then:
      function: truthy
  microcks-operation-extension:
    description: Each operation should declare x-microcks-operation for mock-server compatibility.
    severity: info
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: x-microcks-operation
      function: truthy

Work with this as data

Every ruleset here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for spectral rules

4 MCP tools reach this
  • find_rulesBrowse and filter every ruleset in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This ruleset
curl "https://apis.io/api/v1/rules/programming-quotes-rules"
All spectral rules
curl "https://apis.io/api/v1/rules?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.