PokéAPI · API Governance Rules

PokéAPI API Rules

Spectral linting rules defining API design standards and conventions for PokéAPI.

27 Rules error 8 warn 11 info 8
View Rules File View on GitHub

Rule Categories

info named openapi operation operations pagination path paths pokeapi response schemas servers tags

Rules

error
info-title-required
Info title must be defined.
$.info
warn
info-description-required
Info description must be defined.
$.info
error
info-version-required
Info version must be defined.
$.info
warn
info-license-required
PokéAPI is BSD-3-Clause licensed — info.license must be present.
$.info
error
openapi-version-3
OpenAPI version must be 3.x.
$
error
servers-defined
Servers must be defined.
$
info
pokeapi-base-url
PokéAPI base URL should be https://pokeapi.co/api/v2.
$.servers[*]
warn
paths-kebab-case
PokéAPI path segments are kebab-case (e.g. /berry-firmness, /location-area).
$.paths[*]~
info
paths-no-trailing-slash
Paths should not end with a trailing slash inside the spec.
$.paths[*]~
warn
paths-no-camel-case
PokéAPI path segments must not use camelCase.
$.paths[*]~
error
operations-read-only
All PokéAPI operations are read-only — only GET should be used.
$.paths[*]
error
operation-id-required
Every operation must declare operationId.
$.paths[*][get]
warn
operation-id-camel-case
operationId must be camelCase (e.g. getPokemon, listMoves).
$.paths[*][get].operationId
info
operation-id-list-or-get-prefix
Single-resource operations should be prefixed with `get` and collection operations with `list`.
$.paths[*][get].operationId
error
operation-summary-required
Each operation must have a summary.
$.paths[*][get]
warn
operation-summary-title-case
Operation summaries should use Title Case.
$.paths[*][get].summary
warn
operation-description-required
Each operation must have a description.
$.paths[*][get]
warn
operation-tag-required
Each operation must declare at least one tag.
$.paths[*][get]
info
pagination-limit-required
List endpoints should accept a `limit` query parameter.
$.paths[*][get].parameters[?(@.in=='query')]
warn
path-id-required
Single-resource paths must declare an `id` path parameter.
$.paths[?(@property.match(/\{id\}$/))][get].parameters[?(@.in=='path' && @.name=='id')]
error
response-200-required
Each operation must declare a 200 response.
$.paths[*][get].responses
warn
response-description-required
Every response must declare a description.
$.paths[*][get].responses[*]
warn
response-content-required
200 responses must include an application/json schema.
$.paths[*][get].responses['200'].content
info
tags-defined
Spec must declare a tags collection at the root.
$
info
tags-title-case
Tag names should use Title Case.
$.tags[*].name
info
schemas-defined
Components.schemas must be defined.
$.components
info
named-api-resource-defined
NamedAPIResource is the canonical PokéAPI reference shape — define it.
$.components.schemas

Spectral Ruleset

Raw ↑
rules:
  # =================== INFO ===================
  info-title-required:
    description: Info title must be defined.
    severity: error
    given: "$.info"
    then:
      field: title
      function: truthy

  info-description-required:
    description: Info description must be defined.
    severity: warn
    given: "$.info"
    then:
      field: description
      function: truthy

  info-version-required:
    description: Info version must be defined.
    severity: error
    given: "$.info"
    then:
      field: version
      function: truthy

  info-license-required:
    description: PokéAPI is BSD-3-Clause licensed — info.license must be present.
    severity: warn
    given: "$.info"
    then:
      field: license
      function: truthy

  # =================== OPENAPI VERSION ===================
  openapi-version-3:
    description: OpenAPI version must be 3.x.
    severity: error
    given: "$"
    then:
      field: openapi
      function: pattern
      functionOptions:
        match: "^3\\."

  # =================== SERVERS ===================
  servers-defined:
    description: Servers must be defined.
    severity: error
    given: "$"
    then:
      field: servers
      function: truthy

  pokeapi-base-url:
    description: PokéAPI base URL should be https://pokeapi.co/api/v2.
    severity: info
    given: "$.servers[*]"
    then:
      field: url
      function: pattern
      functionOptions:
        match: "^https://(pokeapi\\.co|beta\\.pokeapi\\.co)/"

  # =================== PATHS — NAMING CONVENTIONS ===================
  paths-kebab-case:
    description: PokéAPI path segments are kebab-case (e.g. /berry-firmness, /location-area).
    severity: warn
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        match: "^/[a-z0-9]+(-[a-z0-9]+)*(\\/\\{[a-z][a-zA-Z0-9_]*\\})?(\\/[a-z]+(-[a-z]+)*)?$"

  paths-no-trailing-slash:
    description: Paths should not end with a trailing slash inside the spec.
    severity: info
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        notMatch: ".+/$"

  paths-no-camel-case:
    description: PokéAPI path segments must not use camelCase.
    severity: warn
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        notMatch: "[a-z][A-Z]"

  # =================== OPERATIONS — HTTP METHODS ===================
  operations-read-only:
    description: All PokéAPI operations are read-only — only GET should be used.
    severity: error
    given: "$.paths[*]"
    then:
      function: enumeration
      functionOptions:
        values:
          - get
          - parameters
          - summary
          - description

  # =================== OPERATIONS — IDENTIFIERS ===================
  operation-id-required:
    description: Every operation must declare operationId.
    severity: error
    given: "$.paths[*][get]"
    then:
      field: operationId
      function: truthy

  operation-id-camel-case:
    description: operationId must be camelCase (e.g. getPokemon, listMoves).
    severity: warn
    given: "$.paths[*][get].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-zA-Z0-9]+$"

  operation-id-list-or-get-prefix:
    description: Single-resource operations should be prefixed with `get` and collection operations with `list`.
    severity: info
    given: "$.paths[*][get].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^(get|list)[A-Z][a-zA-Z0-9]*$"

  # =================== OPERATIONS — SUMMARIES / DESCRIPTIONS ===================
  operation-summary-required:
    description: Each operation must have a summary.
    severity: error
    given: "$.paths[*][get]"
    then:
      field: summary
      function: truthy

  operation-summary-title-case:
    description: Operation summaries should use Title Case.
    severity: warn
    given: "$.paths[*][get].summary"
    then:
      function: pattern
      functionOptions:
        match: "^([A-Z][a-zà-öø-ÿé]*\\s?)+$"

  operation-description-required:
    description: Each operation must have a description.
    severity: warn
    given: "$.paths[*][get]"
    then:
      field: description
      function: truthy

  operation-tag-required:
    description: Each operation must declare at least one tag.
    severity: warn
    given: "$.paths[*][get]"
    then:
      field: tags
      function: schema
      functionOptions:
        schema:
          type: array
          minItems: 1

  # =================== PARAMETERS ===================
  pagination-limit-required:
    description: List endpoints should accept a `limit` query parameter.
    severity: info
    given: "$.paths[*][get].parameters[?(@.in=='query')]"
    then:
      function: truthy

  path-id-required:
    description: Single-resource paths must declare an `id` path parameter.
    severity: warn
    given: "$.paths[?(@property.match(/\\{id\\}$/))][get].parameters[?(@.in=='path' && @.name=='id')]"
    then:
      function: truthy

  # =================== RESPONSES ===================
  response-200-required:
    description: Each operation must declare a 200 response.
    severity: error
    given: "$.paths[*][get].responses"
    then:
      field: "200"
      function: truthy

  response-description-required:
    description: Every response must declare a description.
    severity: warn
    given: "$.paths[*][get].responses[*]"
    then:
      field: description
      function: truthy

  response-content-required:
    description: 200 responses must include an application/json schema.
    severity: warn
    given: "$.paths[*][get].responses['200'].content"
    then:
      field: application/json
      function: truthy

  # =================== TAGS ===================
  tags-defined:
    description: Spec must declare a tags collection at the root.
    severity: info
    given: "$"
    then:
      field: tags
      function: truthy

  tags-title-case:
    description: Tag names should use Title Case.
    severity: info
    given: "$.tags[*].name"
    then:
      function: pattern
      functionOptions:
        match: "^[A-Z]"

  # =================== SCHEMAS ===================
  schemas-defined:
    description: Components.schemas must be defined.
    severity: info
    given: "$.components"
    then:
      field: schemas
      function: truthy

  named-api-resource-defined:
    description: NamedAPIResource is the canonical PokéAPI reference shape — define it.
    severity: info
    given: "$.components.schemas"
    then:
      field: NamedAPIResource
      function: truthy