YGOPRODeck · API Governance Rules

YGOPRODeck API Rules

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

43 Rules error 20 warn 16 info 7
View Rules File View on GitHub

Rule Categories

external get global info microcks no openapi operation parameter paths rate response schema servers tags

Rules

warn
info-title-ygoprodeck-prefix
API title must start with "YGOPRODeck".
$.info.title
error
info-description-required
API description is required and should explain scope and rate limits.
$.info
error
info-version-required
API version must be specified (YGOPRODeck convention is `v7`).
$.info
warn
info-contact-required
A contact block must be present so consumers can reach the API provider.
$.info
warn
info-license-required
License block must be present.
$.info
warn
info-terms-of-service-required
A terms-of-service URL is required (the API Guide link).
$.info
error
openapi-version-3-0
OpenAPI document must use 3.0.x.
$.openapi
error
servers-defined
At least one server must be defined.
$
error
servers-https-only
Servers must use HTTPS.
$.servers[*].url
warn
servers-ygoprodeck-host
Production server must be db.ygoprodeck.com.
$.servers[*].url
warn
servers-description-required
Each server must have a description.
$.servers[*]
error
paths-lowercase
Path segments must be lowercase.
$.paths[*]~
info
paths-php-suffix
YGOPRODeck v7 endpoints end with `.php`.
$.paths[*]~
error
paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths[*]~
error
paths-no-query-string
Path keys must not include a query string — query params belong in `parameters`.
$.paths[*]~
error
operation-summary-required
Every operation must have a summary.
$.paths[*][get,post,put,patch,delete]
error
operation-description-required
Every operation must have a description.
$.paths[*][get,post,put,patch,delete]
error
operation-id-required
Every operation must declare an operationId.
$.paths[*][get,post,put,patch,delete]
error
operation-id-camel-case
operationId must be camelCase.
$.paths[*][get,post,put,patch,delete].operationId
warn
operation-id-verb-prefix
operationId should start with a CRUD-style verb (get, list, search, create, update, delete).
$.paths[*][get,post,put,patch,delete].operationId
warn
operation-summary-ygoprodeck-prefix
Operation summaries should start with `YGOPRODeck`.
$.paths[*][get,post,put,patch,delete].summary
error
operation-tags-required
Every operation must declare at least one tag.
$.paths[*][get,post,put,patch,delete]
error
global-tags-defined
A global `tags` array must be declared at the root of the spec.
$
warn
tags-have-description
Each global tag must include a description.
$.tags[*]
warn
tags-title-case
Tag names should be Title Case (e.g. `Cards`, `Card Sets`, `Reference Data`).
$.tags[*].name
error
parameter-description-required
Every parameter must have a description.
$.paths[*][get,post,put,patch,delete].parameters[*]
error
parameter-schema-required
Every parameter must declare a schema with a type.
$.paths[*][get,post,put,patch,delete].parameters[*]
warn
parameter-snake-case
Query parameter names must be snake_case (matches YGOPRODeck native style).
$.paths[*][get,post,put,patch,delete].parameters[?(@.in=='query')].name
info
parameter-example-encouraged
Parameters should include an `example` value to help client developers.
$.paths[*][get,post,put,patch,delete].parameters[*]
error
response-200-required
Every operation must define a `200` response.
$.paths[*][get,post,put,patch,delete].responses
error
response-description-required
Every response must include a description.
$.paths[*][get,post,put,patch,delete].responses[*]
warn
response-application-json
Success responses must use `application/json`.
$.paths[*][get,post,put,patch,delete].responses.200.content
info
response-400-for-filterable-operations
Operations that accept user-supplied filter parameters should declare a `400` response.
$.paths[*][get,post,put,patch,delete][?(@.parameters)]
warn
schema-property-snake-case
Schema property names must be snake_case (matches YGOPRODeck native field naming).
$.components.schemas[*].properties[*]~
warn
schema-description-required
Every top-level schema in `components.schemas` should have a description.
$.components.schemas[*]
error
schema-type-required
Every top-level schema must declare a `type`.
$.components.schemas[*]
warn
no-security-schemes
YGOPRODeck v7 is unauthenticated; no security schemes should be declared.
$.components.securitySchemes
warn
no-global-security
YGOPRODeck v7 has no global security; the `security` array should be empty or absent.
$.security
error
get-only
YGOPRODeck v7 exposes GET-only endpoints. Other HTTP methods should not appear.
$.paths[*]
info
external-docs-encouraged
Provide `externalDocs` pointing at the YGOPRODeck API Guide.
$
info
external-docs-points-at-api-guide
externalDocs.url should point at the YGOPRODeck API Guide.
$.externalDocs.url
info
rate-limit-noted-in-description
The API description should mention the documented rate limit.
$.info.description
info
microcks-operation-extension
Each operation should declare an `x-microcks-operation` block so the spec is mock-server ready.
$.paths[*][get,post,put,patch,delete]

Spectral Ruleset

Raw ↑
# Spectral ruleset for the YGOPRODeck Yu-Gi-Oh! Card Database API.
#
# Derived from the YGOPRODeck v7 API conventions:
#   - Single host: db.ygoprodeck.com/api/v7
#   - All endpoints are `.php` GET requests (PHP-style flat paths, no REST nouns)
#   - Query parameters use snake_case (e.g. `set_code`, `has_effect`, `tcgplayer_data`)
#   - Schema properties use snake_case (e.g. `card_sets`, `set_rarity_code`, `tcg_date`)
#   - operationIds use camelCase verb-noun (`searchCards`, `getRandomCard`, `listCardSets`)
#   - Tags use Title Case (e.g. `Cards`, `Card Sets`, `Reference Data`)
#   - Summaries are prefixed with `YGOPRODeck` and Title-Cased

extends: [[spectral:oas, recommended]]

rules:

  # ── INFO / METADATA ──────────────────────────────────────────────────────
  info-title-ygoprodeck-prefix:
    description: API title must start with "YGOPRODeck".
    message: '{{property}} should start with "YGOPRODeck"'
    severity: warn
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        match: '^YGOPRODeck'

  info-description-required:
    description: API description is required and should explain scope and rate limits.
    message: '{{property}} must be present and at least 80 characters long.'
    severity: error
    given: $.info
    then:
      - field: description
        function: truthy
      - field: description
        function: length
        functionOptions:
          min: 80

  info-version-required:
    description: API version must be specified (YGOPRODeck convention is `v7`).
    severity: error
    given: $.info
    then:
      field: version
      function: truthy

  info-contact-required:
    description: A contact block must be present so consumers can reach the API provider.
    severity: warn
    given: $.info
    then:
      field: contact
      function: truthy

  info-license-required:
    description: License block must be present.
    severity: warn
    given: $.info
    then:
      field: license
      function: truthy

  info-terms-of-service-required:
    description: A terms-of-service URL is required (the API Guide link).
    severity: warn
    given: $.info
    then:
      field: termsOfService
      function: truthy

  # ── OPENAPI VERSION ─────────────────────────────────────────────────────
  openapi-version-3-0:
    description: OpenAPI document must use 3.0.x.
    message: '{{property}} must match 3.0.x.'
    severity: error
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: '^3\.0\.\d+$'

  # ── SERVERS ─────────────────────────────────────────────────────────────
  servers-defined:
    description: At least one server must be defined.
    severity: error
    given: $
    then:
      field: servers
      function: truthy

  servers-https-only:
    description: Servers must use HTTPS.
    message: '{{property}} must use HTTPS.'
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: '^https://'

  servers-ygoprodeck-host:
    description: Production server must be db.ygoprodeck.com.
    message: '{{property}} must point at db.ygoprodeck.com/api/v7.'
    severity: warn
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: '^https://db\.ygoprodeck\.com/api/v7'

  servers-description-required:
    description: Each server must have a description.
    severity: warn
    given: $.servers[*]
    then:
      field: description
      function: truthy

  # ── PATHS — NAMING CONVENTIONS ──────────────────────────────────────────
  # YGOPRODeck uses flat PHP-style paths. We enforce the actual convention.
  paths-lowercase:
    description: Path segments must be lowercase.
    message: '{{property}} must use lowercase path segments.'
    severity: error
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        match: '^/[a-z0-9./{}_-]+$'

  paths-php-suffix:
    description: YGOPRODeck v7 endpoints end with `.php`.
    message: '{{property}} should end with `.php` to match the YGOPRODeck v7 convention.'
    severity: info
    given: $.paths[*]~
    then:
      function: pattern
      functionOptions:
        match: '\.php$'

  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-string:
    description: Path keys must not include a query string — query params belong in `parameters`.
    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: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: description
      function: truthy

  operation-id-required:
    description: Every operation must declare an operationId.
    severity: error
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: operationId
      function: truthy

  operation-id-camel-case:
    description: operationId must be camelCase.
    message: '{{value}} must be camelCase (lowercase first letter, no separators).'
    severity: error
    given: $.paths[*][get,post,put,patch,delete].operationId
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-zA-Z0-9]+$'

  operation-id-verb-prefix:
    description: operationId should start with a CRUD-style verb (get, list, search, create, update, delete).
    message: '{{value}} should start with `get`, `list`, `search`, `create`, `update`, or `delete`.'
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].operationId
    then:
      function: pattern
      functionOptions:
        match: '^(get|list|search|create|update|delete|check)'

  operation-summary-ygoprodeck-prefix:
    description: Operation summaries should start with `YGOPRODeck`.
    message: '{{value}} should start with `YGOPRODeck`.'
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].summary
    then:
      function: pattern
      functionOptions:
        match: '^YGOPRODeck'

  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

  # ── TAGS ────────────────────────────────────────────────────────────────
  global-tags-defined:
    description: A global `tags` array must be declared at the root of the spec.
    severity: error
    given: $
    then:
      field: tags
      function: truthy

  tags-have-description:
    description: Each global tag must include a description.
    severity: warn
    given: $.tags[*]
    then:
      field: description
      function: truthy

  tags-title-case:
    description: Tag names should be Title Case (e.g. `Cards`, `Card Sets`, `Reference Data`).
    message: '{{value}} must be Title Case.'
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: '^([A-Z][a-z0-9]*)(\s+[A-Z][a-z0-9]*)*$'

  # ── PARAMETERS ──────────────────────────────────────────────────────────
  parameter-description-required:
    description: Every parameter must have a description.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].parameters[*]
    then:
      field: description
      function: truthy

  parameter-schema-required:
    description: Every parameter must declare a schema with a type.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].parameters[*]
    then:
      field: schema
      function: truthy

  parameter-snake-case:
    description: Query parameter names must be snake_case (matches YGOPRODeck native style).
    message: '{{value}} must be snake_case.'
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in=='query')].name
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-z0-9_]*$'

  parameter-example-encouraged:
    description: Parameters should include an `example` value to help client developers.
    severity: info
    given: $.paths[*][get,post,put,patch,delete].parameters[*]
    then:
      field: example
      function: truthy

  # ── RESPONSES ───────────────────────────────────────────────────────────
  response-200-required:
    description: Every operation must define a `200` response.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses
    then:
      field: '200'
      function: truthy

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

  response-application-json:
    description: Success responses must use `application/json`.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete].responses.200.content
    then:
      field: application/json
      function: truthy

  response-400-for-filterable-operations:
    description: Operations that accept user-supplied filter parameters should declare a `400` response.
    severity: info
    given: $.paths[*][get,post,put,patch,delete][?(@.parameters)]
    then:
      field: responses.400
      function: truthy

  # ── SCHEMAS — PROPERTY NAMING ───────────────────────────────────────────
  schema-property-snake-case:
    description: Schema property names must be snake_case (matches YGOPRODeck native field naming).
    message: '{{property}} must be snake_case.'
    severity: warn
    given: '$.components.schemas[*].properties[*]~'
    then:
      function: pattern
      functionOptions:
        match: '^[a-z][a-z0-9_]*$'

  schema-description-required:
    description: Every top-level schema in `components.schemas` should have a description.
    severity: warn
    given: $.components.schemas[*]
    then:
      field: description
      function: truthy

  schema-type-required:
    description: Every top-level schema must declare a `type`.
    severity: error
    given: $.components.schemas[*]
    then:
      field: type
      function: truthy

  # ── SECURITY ────────────────────────────────────────────────────────────
  # YGOPRODeck is unauthenticated — we positively enforce the absence of auth
  # to keep accidental "leaks" out of the spec.
  no-security-schemes:
    description: YGOPRODeck v7 is unauthenticated; no security schemes should be declared.
    severity: warn
    given: $.components.securitySchemes
    then:
      function: falsy

  no-global-security:
    description: YGOPRODeck v7 has no global security; the `security` array should be empty or absent.
    severity: warn
    given: $.security
    then:
      function: falsy

  # ── HTTP METHOD CONVENTIONS ─────────────────────────────────────────────
  get-only:
    description: YGOPRODeck v7 exposes GET-only endpoints. Other HTTP methods should not appear.
    message: 'Only GET operations are valid on YGOPRODeck v7.'
    severity: error
    given: $.paths[*]
    then:
      function: schema
      functionOptions:
        schema:
          type: object
          not:
            anyOf:
              - required: [post]
              - required: [put]
              - required: [patch]
              - required: [delete]

  # ── GENERAL QUALITY ─────────────────────────────────────────────────────
  external-docs-encouraged:
    description: Provide `externalDocs` pointing at the YGOPRODeck API Guide.
    severity: info
    given: $
    then:
      field: externalDocs
      function: truthy

  external-docs-points-at-api-guide:
    description: externalDocs.url should point at the YGOPRODeck API Guide.
    severity: info
    given: $.externalDocs.url
    then:
      function: pattern
      functionOptions:
        match: 'ygoprodeck\.com/api-guide'

  rate-limit-noted-in-description:
    description: The API description should mention the documented rate limit.
    severity: info
    given: $.info.description
    then:
      function: pattern
      functionOptions:
        match: '20 requests per second|rate limit'

  microcks-operation-extension:
    description: Each operation should declare an `x-microcks-operation` block so the spec is mock-server ready.
    severity: info
    given: $.paths[*][get,post,put,patch,delete]
    then:
      field: x-microcks-operation
      function: truthy