Punk API · API Governance Rules

Punk API API Rules

Spectral linting rules defining API design standards and conventions for Punk API.

36 Rules error 11 warn 21 info 4
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

get info no openapi operation parameter paths query read response schema servers tag

Rules

warn
info-title-punkapi-prefix
Spec title should begin with "Punk API".
$.info
error
info-description-required
Spec must include a non-empty description.
$.info
error
info-version-required
Spec must declare a version.
$.info
warn
info-license-required
Spec must include license info (Punk API is MIT-licensed).
$.info
warn
info-deprecation-status
Spec must declare x-status (deprecated for the public Punk API).
$.info
warn
openapi-version-3-0-3
Specs must target OpenAPI 3.0.x.
$.openapi
error
servers-https-required
Production server URLs must use HTTPS.
$.servers[0].url
warn
servers-punkapi-host
Production server URL must point at api.punkapi.com/v2.
$.servers[0].url
error
paths-lowercase
Paths must be lowercase.
$.paths.*~
error
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths.*~
warn
paths-beers-resource
Punk API only exposes /beers, /beers/{beerId}, and /beers/random.
$.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-punkapi-prefix
Every operation summary must start with "Punk API".
$.paths.*[get,post,put,patch,delete].summary
error
operation-operationid-required
Every operation must declare an operationId.
$.paths.*[get,post,put,patch,delete]
warn
operation-operationid-camelcase
operationId must be camelCase.
$.paths.*[get,post,put,patch,delete].operationId
info
operation-operationid-verb-prefix
operationId should begin with list/get.
$.paths.*[get,post,put,patch,delete].operationId
error
operation-tags-required
Every operation must declare at least one tag.
$.paths.*[get,post,put,patch,delete]
warn
operation-tag-beers
All operations must be tagged 'Beers'.
$.paths.*[get,post,put,patch,delete].tags
info
operation-microcks-extension
Every operation should declare x-microcks-operation.
$.paths.*[get,post,put,patch,delete]
warn
tag-title-case
Global tag names must use Title Case.
$.tags[*].name
warn
tag-description-required
Each global tag must include a description.
$.tags[*]
warn
parameter-description-required
Every parameter must have a description.
$.paths.*[get,post,put,patch,delete].parameters[*]
warn
parameter-snake-or-camel
Query parameter names use snake_case (Punk API convention) or camelCase (beerId).
$.paths.*[get,post,put,patch,delete].parameters[*].name
info
query-pagination-pair
Pagination uses the pair (page, per_page).
$.paths.*[get].parameters[?(@.in=='query')].name
error
response-success-required
Every operation must define a 2xx success response.
$.paths.*[get,post,put,patch,delete].responses
warn
response-description-required
Every response must have a description.
$.paths.*[get,post,put,patch,delete].responses.*
warn
response-json-content
Success responses must return application/json.
$.paths.*[get,post,put,patch,delete].responses[?(@property.match(/^2\d\d$/))].content
info
response-error-envelope
4xx/5xx responses should reference the shared Error schema.
$.paths.*[get,post,put,patch,delete].responses[?(@property.match(/^(4|5)\d\d$/))].content.application/json.schema
warn
schema-property-snake-case
Beer schema property names use snake_case (matches the Punk API JSON shape).
$.components.schemas.Beer.properties.*~
warn
schema-description-required
Top-level schemas must include a description.
$.components.schemas.*
error
schema-type-required
Top-level schemas must declare a type.
$.components.schemas.*
warn
schema-beer-required-fields
Beer schema must require id, name, abv, ingredients, method.
$.components.schemas.Beer
error
get-no-request-body
GET operations must not declare a request body.
$.paths.*.get
warn
read-only-surface
Punk API exposes a read-only surface (GET only).
$.paths.*
warn
no-empty-descriptions
Descriptions must be non-empty when present.
$..description

Spectral Ruleset

Raw ↑
extends: spectral:oas

rules:

  # ── INFO / METADATA ──────────────────────────────────────────────
  info-title-punkapi-prefix:
    description: Spec title should begin with "Punk API".
    severity: warn
    given: $.info
    then:
      field: title
      function: pattern
      functionOptions:
        match: '^Punk API'

  info-description-required:
    description: Spec must include a non-empty description.
    severity: error
    given: $.info
    then:
      field: description
      function: truthy

  info-version-required:
    description: Spec must declare a version.
    severity: error
    given: $.info
    then:
      field: version
      function: truthy

  info-license-required:
    description: Spec must include license info (Punk API is MIT-licensed).
    severity: warn
    given: $.info
    then:
      field: license
      function: truthy

  info-deprecation-status:
    description: Spec must declare x-status (deprecated for the public Punk API).
    severity: warn
    given: $.info
    then:
      field: x-status
      function: truthy

  # ── OPENAPI VERSION ──────────────────────────────────────────────
  openapi-version-3-0-3:
    description: Specs must target OpenAPI 3.0.x.
    severity: warn
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: '^3\.0\.'

  # ── SERVERS ──────────────────────────────────────────────────────
  servers-https-required:
    description: Production server URLs must use HTTPS.
    severity: error
    given: $.servers[0].url
    then:
      function: pattern
      functionOptions:
        match: '^https://'

  servers-punkapi-host:
    description: Production server URL must point at api.punkapi.com/v2.
    severity: warn
    given: $.servers[0].url
    then:
      function: pattern
      functionOptions:
        match: 'api\.punkapi\.com/v2'

  # ── PATHS — NAMING ───────────────────────────────────────────────
  paths-lowercase:
    description: Paths must be lowercase.
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: '^/[a-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-beers-resource:
    description: Punk API only exposes /beers, /beers/{beerId}, and /beers/random.
    severity: warn
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: '^/beers(/.*)?$'

  # ── 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-punkapi-prefix:
    description: Every operation summary must start with "Punk API".
    severity: warn
    given: $.paths.*[get,post,put,patch,delete].summary
    then:
      function: pattern
      functionOptions:
        match: '^Punk API'

  operation-operationid-required:
    description: Every operation must declare 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: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]*$'

  operation-operationid-verb-prefix:
    description: operationId should begin with list/get.
    severity: info
    given: $.paths.*[get,post,put,patch,delete].operationId
    then:
      function: pattern
      functionOptions:
        match: '^(list|get)[A-Z]'

  operation-tags-required:
    description: Every operation must declare at least one tag.
    severity: error
    given: $.paths.*[get,post,put,patch,delete]
    then:
      field: tags
      function: truthy

  operation-tag-beers:
    description: All operations must be tagged 'Beers'.
    severity: warn
    given: $.paths.*[get,post,put,patch,delete].tags
    then:
      function: schema
      functionOptions:
        schema:
          type: array
          contains:
            const: Beers

  operation-microcks-extension:
    description: Every operation should declare x-microcks-operation.
    severity: info
    given: $.paths.*[get,post,put,patch,delete]
    then:
      field: x-microcks-operation
      function: truthy

  # ── TAGS ─────────────────────────────────────────────────────────
  tag-title-case:
    description: Global tag names must use Title Case.
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: '^[A-Z][a-z]+$'

  tag-description-required:
    description: Each global tag must include 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-snake-or-camel:
    description: Query parameter names use snake_case (Punk API convention) or camelCase (beerId).
    severity: warn
    given: $.paths.*[get,post,put,patch,delete].parameters[*].name
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9_]*$'

  query-pagination-pair:
    description: Pagination uses the pair (page, per_page).
    severity: info
    given: $.paths.*[get].parameters[?(@.in=='query')].name
    then:
      function: pattern
      functionOptions:
        match: '^(page|per_page|abv_gt|abv_lt|ibu_gt|ibu_lt|ebc_gt|ebc_lt|beer_name|hops|malt|yeast|food|brewed_before|brewed_after)$'

  # ── RESPONSES ────────────────────────────────────────────────────
  response-success-required:
    description: Every operation must define a 2xx success response.
    severity: error
    given: $.paths.*[get,post,put,patch,delete].responses
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          patternProperties:
            '^2\d\d$': {}
          minProperties: 1

  response-description-required:
    description: Every response must have a description.
    severity: warn
    given: $.paths.*[get,post,put,patch,delete].responses.*
    then:
      field: description
      function: truthy

  response-json-content:
    description: Success responses must return application/json.
    severity: warn
    given: $.paths.*[get,post,put,patch,delete].responses[?(@property.match(/^2\d\d$/))].content
    then:
      field: application/json
      function: truthy

  response-error-envelope:
    description: 4xx/5xx responses should reference the shared Error schema.
    severity: info
    given: $.paths.*[get,post,put,patch,delete].responses[?(@property.match(/^(4|5)\d\d$/))].content.application/json.schema
    then:
      field: $ref
      function: truthy

  # ── SCHEMAS ──────────────────────────────────────────────────────
  schema-property-snake-case:
    description: Beer schema property names use snake_case (matches the Punk API JSON shape).
    severity: warn
    given: $.components.schemas.Beer.properties.*~
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-z0-9_]*$'

  schema-description-required:
    description: Top-level schemas must include a description.
    severity: warn
    given: $.components.schemas.*
    then:
      field: description
      function: truthy

  schema-type-required:
    description: Top-level schemas must declare a type.
    severity: error
    given: $.components.schemas.*
    then:
      field: type
      function: truthy

  schema-beer-required-fields:
    description: Beer schema must require id, name, abv, ingredients, method.
    severity: warn
    given: $.components.schemas.Beer
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          properties:
            required:
              type: array
              contains: { const: id }
          required: [required]

  # ── 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

  read-only-surface:
    description: Punk API exposes a read-only surface (GET only).
    severity: warn
    given: $.paths.*
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          not:
            anyOf:
              - required: [post]
              - required: [put]
              - required: [patch]
              - required: [delete]

  # ── GENERAL ──────────────────────────────────────────────────────
  no-empty-descriptions:
    description: Descriptions must be non-empty when present.
    severity: warn
    given: '$..description'
    then:
      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/punkapi-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.