An API of Ice And Fire · API Governance Rules

An API of Ice And Fire API Rules

Spectral linting rules defining API design standards and conventions for An API of Ice And Fire.

53 Rules error 16 warn 26 info 11
View Rules File View on GitHub

Rule Categories

error examples get http info no openapi operation parameter path paths query response schema security servers tags

Rules

error
info-title-format
info.title MUST equal "An API of Ice And Fire".
$.info.title
error
info-description-required
info.description MUST be present and at least 80 characters.
$.info
error
info-version-required
info.version MUST be present.
$.info
warn
info-contact-required
info.contact with name and url MUST be present.
$.info
warn
info-license-required
info.license MUST be present (BSD-style).
$.info
error
openapi-version-three
OpenAPI version MUST be 3.x.
$.openapi
error
servers-defined
At least one server MUST be defined.
$.servers
error
servers-https-only
Server URLs MUST use HTTPS.
$.servers[*].url
warn
servers-anapioficeandfire-host
Production server MUST point at anapioficeandfire.com.
$.servers[*].url
warn
servers-description-required
Every server MUST have a description.
$.servers[*]
warn
paths-kebab-case
Path segments MUST be lowercase kebab-case (plural collection nouns).
$.paths.*~
warn
paths-no-trailing-slash
Paths MUST NOT end with a trailing slash (except root `/`).
$.paths.*~
error
paths-no-query-strings
Paths MUST NOT include query strings.
$.paths.*~
info
paths-plural-collection-nouns
Top-level resources use plural nouns (books, characters, houses).
$.paths.*~
error
operation-summary-required
Every operation MUST have a summary.
#Operation
warn
operation-summary-provider-prefix
Operation summaries MUST start with "An API of Ice And Fire".
#Operation.summary
error
operation-description-required
Every operation MUST have a description.
#Operation
error
operation-id-required
Every operation MUST have an operationId.
#Operation
error
operation-id-camel-case
operationId MUST be camelCase.
#Operation.operationId
warn
operation-id-verb-prefix
operationId SHOULD start with get, list, create, update, or delete.
#Operation.operationId
error
operation-tags-required
Every operation MUST have at least one tag.
#Operation
info
operation-microcks-extension
Operations SHOULD declare x-microcks-operation for mock-server compatibility.
#Operation
warn
tags-global-defined
Global `tags` array MUST be defined.
$
warn
tags-have-description
Every global tag MUST have a description.
$.tags[*]
warn
tags-title-case
Tag names MUST be Title Case single words (Books, Characters, Houses, Root).
$.tags[*].name
warn
parameter-description-required
Every parameter MUST have a description.
$..parameters[?(@.name)]
warn
parameter-camel-case
Query and path parameter names MUST be camelCase.
$..parameters[?(@.name)].name
warn
parameter-pagination-naming
Pagination MUST use `page` + `pageSize` (not page/limit, page/size, or offset/limit).
$..parameters[?(@.in=='query')].name
info
parameter-page-default
The `page` parameter SHOULD default to 1.
$.components.parameters.Page.schema
warn
parameter-page-size-max-fifty
The `pageSize` parameter MUST cap at 50.
$.components.parameters.PageSize.schema
error
response-success-required
Every operation MUST declare a 200 response.
#Operation.responses
warn
response-not-found-on-get-by-id
get-by-id operations MUST declare a 404 response.
$.paths[*][get].responses
info
response-rate-limited
Every operation SHOULD document the 403 rate-limit response.
#Operation.responses
info
response-conditional-not-modified
GET operations SHOULD document the 304 Not Modified response for conditional caching.
$.paths[*][get].responses
error
response-json-content-type
200 responses MUST use application/json.
$.paths[*][get,post,put,patch,delete].responses['200'].content
warn
response-description-required
Every response MUST have a description.
$.paths[*][get,post,put,patch,delete].responses[*]
warn
response-pagination-link-header
Collection list responses SHOULD include the RFC 5988 Link header.
$.paths[/books,/characters,/houses][get].responses['200'].headers
info
response-caching-headers
GET responses SHOULD include ETag, Last-Modified, and Cache-Control headers.
$.paths[*][get].responses['200'].headers
warn
schema-property-camel-case
Schema property names MUST be camelCase.
$.components.schemas[*].properties.*~
error
schema-type-required
Every component schema MUST declare a `type`.
#Schema
warn
schema-description-required
Every component schema MUST have a description.
#Schema
info
schema-url-self-link
Resource schemas SHOULD include a `url` self-link.
$.components.schemas[?(@.type=='object')]
warn
schema-related-resource-uri-format
Schema properties named like related-resource refs MUST use format=uri.
$.components.schemas[*].properties[url,father,mother,spouse,overlord,founder,currentLord,heir]
info
security-not-required
This API is unauthenticated; global `security` MUST NOT require credentials.
$
warn
http-only-get
An API of Ice And Fire is read-only — only GET operations are allowed.
$.paths[*]
error
get-no-request-body
GET operations MUST NOT have a requestBody.
$.paths[*][get]
warn
no-empty-descriptions
Descriptions MUST NOT be empty strings.
$..description
info
examples-encouraged
Operations SHOULD include named examples on 200 responses.
$.paths[*][get].responses['200'].content.application/json
warn
path-params-casing
Path parameters should be snake_case (the dominant convention in this API).
$.paths[*].parameters[?(@.in=='path')].name
info
query-params-casing
Query parameters should be snake_case (the dominant convention in this API).
$.paths[*][get,post,put,patch,delete].parameters[?(@.in=='query')]
warn
schema-names-casing
Component schema names should be PascalCase (the dominant convention in this API).
$.components.schemas
info
schema-properties-casing
Schema properties should be snake_case (the dominant convention in this API).
$.components.schemas[*].properties
warn
error-schema-defined
A shared error schema (Error) should be defined for error payloads.
$.components.schemas

Spectral Ruleset

Raw ↑
# an-api-of-ice-and-fire — Spectral ruleset (strengthened)
# Plain Spectral. Existing hand-authored rules preserved; measured rules added
# from this provider's own OpenAPI conventions by strengthen_ruleset.py,
# then self-validated against the spec.
#
# Provenance:
#   - servers-https-only: 100% of servers already https (error)
#   - servers-expected-domain: 1/1 servers on anapioficeandfire.com
#   - path-params-casing: snake @ 100% (n=3)
#   - query-params-casing: snake @ 52% (n=23)
#   - operationid-casing: camel @ 100% (n=7)
#   - schema-names-casing: pascal @ 100% (n=5)
#   - schema-properties-casing: snake @ 74% (n=47)
#   - error-schema-defined: Error
#   - operation-documents-403: 86% adherence
#   - pagination params observed: ['page', 'pageSize']
#   - merge: kept 48 existing, added 5 measured, upgraded 0
#   - added: path-params-casing, query-params-casing, schema-names-casing, schema-properties-casing, error-schema-defined
extends:
  - spectral:oas
rules:
  info-title-format:
    description: info.title MUST equal "An API of Ice And Fire".
    message: '{{property}} should be "An API of Ice And Fire"'
    severity: error
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        match: ^An API of Ice And Fire$
  info-description-required:
    description: info.description MUST be present and at least 80 characters.
    severity: error
    given: $.info
    then:
    - field: description
      function: truthy
    - field: description
      function: length
      functionOptions:
        min: 80
  info-version-required:
    description: info.version MUST be present.
    severity: error
    given: $.info
    then:
      field: version
      function: truthy
  info-contact-required:
    description: info.contact with name and url MUST be present.
    severity: warn
    given: $.info
    then:
    - field: contact.name
      function: truthy
    - field: contact.url
      function: truthy
  info-license-required:
    description: info.license MUST be present (BSD-style).
    severity: warn
    given: $.info
    then:
    - field: license.name
      function: truthy
    - field: license.url
      function: truthy
  openapi-version-three:
    description: OpenAPI version MUST be 3.x.
    severity: error
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: ^3\.
  servers-defined:
    description: At least one server MUST be defined.
    severity: error
    given: $.servers
    then:
      function: length
      functionOptions:
        min: 1
  servers-https-only:
    description: Server URLs MUST use HTTPS.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: ^https://
  servers-anapioficeandfire-host:
    description: Production server MUST point at anapioficeandfire.com.
    severity: warn
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: anapioficeandfire\.com/api
  servers-description-required:
    description: Every server MUST have a description.
    severity: warn
    given: $.servers[*]
    then:
      field: description
      function: truthy
  paths-kebab-case:
    description: Path segments MUST be lowercase kebab-case (plural collection nouns).
    severity: warn
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: ^(/|(/[a-z][a-z0-9-]*(/\{[a-zA-Z][a-zA-Z0-9]*\})?)+)$
  paths-no-trailing-slash:
    description: Paths MUST NOT end with a trailing slash (except root `/`).
    severity: warn
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: .+/$
  paths-no-query-strings:
    description: Paths MUST NOT include query strings.
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: \?
  paths-plural-collection-nouns:
    description: Top-level resources use plural nouns (books, characters, houses).
    severity: info
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: ^(/|/(books|characters|houses)(/.*)?)$
  operation-summary-required:
    description: Every operation MUST have a summary.
    severity: error
    given: '#Operation'
    then:
      field: summary
      function: truthy
  operation-summary-provider-prefix:
    description: Operation summaries MUST start with "An API of Ice And Fire".
    severity: warn
    given: '#Operation.summary'
    then:
      function: pattern
      functionOptions:
        match: '^An API of Ice And Fire '
  operation-description-required:
    description: Every operation MUST have a description.
    severity: error
    given: '#Operation'
    then:
      field: description
      function: truthy
  operation-id-required:
    description: Every operation MUST have an operationId.
    severity: error
    given: '#Operation'
    then:
      field: operationId
      function: truthy
  operation-id-camel-case:
    description: operationId MUST be camelCase.
    severity: error
    given: '#Operation.operationId'
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  operation-id-verb-prefix:
    description: operationId SHOULD start with get, list, create, update, or delete.
    severity: warn
    given: '#Operation.operationId'
    then:
      function: pattern
      functionOptions:
        match: ^(get|list|create|update|delete)[A-Z]
  operation-tags-required:
    description: Every operation MUST have at least one tag.
    severity: error
    given: '#Operation'
    then:
      field: tags
      function: length
      functionOptions:
        min: 1
  operation-microcks-extension:
    description: Operations SHOULD declare x-microcks-operation for mock-server compatibility.
    severity: info
    given: '#Operation'
    then:
      field: x-microcks-operation
      function: truthy
  tags-global-defined:
    description: Global `tags` array MUST be defined.
    severity: warn
    given: $
    then:
      field: tags
      function: truthy
  tags-have-description:
    description: Every global tag MUST have a description.
    severity: warn
    given: $.tags[*]
    then:
      field: description
      function: truthy
  tags-title-case:
    description: Tag names MUST be Title Case single words (Books, Characters, Houses, Root).
    severity: warn
    given: $.tags[*].name
    then:
      function: pattern
      functionOptions:
        match: ^[A-Z][a-zA-Z]+$
  parameter-description-required:
    description: Every parameter MUST have a description.
    severity: warn
    given: $..parameters[?(@.name)]
    then:
      field: description
      function: truthy
  parameter-camel-case:
    description: Query and path parameter names MUST be camelCase.
    severity: warn
    given: $..parameters[?(@.name)].name
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  parameter-pagination-naming:
    description: Pagination MUST use `page` + `pageSize` (not page/limit, page/size, or offset/limit).
    severity: warn
    given: $..parameters[?(@.in=='query')].name
    then:
      function: pattern
      functionOptions:
        notMatch: ^(limit|size|offset|per_page|perPage)$
  parameter-page-default:
    description: The `page` parameter SHOULD default to 1.
    severity: info
    given: $.components.parameters.Page.schema
    then:
      field: default
      function: truthy
  parameter-page-size-max-fifty:
    description: The `pageSize` parameter MUST cap at 50.
    severity: warn
    given: $.components.parameters.PageSize.schema
    then:
      field: maximum
      function: truthy
  response-success-required:
    description: Every operation MUST declare a 200 response.
    severity: error
    given: '#Operation.responses'
    then:
      field: '200'
      function: truthy
  response-not-found-on-get-by-id:
    description: get-by-id operations MUST declare a 404 response.
    severity: warn
    given: $.paths[*][get].responses
    then:
      field: '404'
      function: defined
  response-rate-limited:
    description: Every operation SHOULD document the 403 rate-limit response.
    severity: info
    given: '#Operation.responses'
    then:
      field: '403'
      function: defined
  response-conditional-not-modified:
    description: GET operations SHOULD document the 304 Not Modified response for conditional caching.
    severity: info
    given: $.paths[*][get].responses
    then:
      field: '304'
      function: defined
  response-json-content-type:
    description: 200 responses MUST use application/json.
    severity: error
    given: $.paths[*][get,post,put,patch,delete].responses['200'].content
    then:
      field: application/json
      function: truthy
  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-pagination-link-header:
    description: Collection list responses SHOULD include the RFC 5988 Link header.
    severity: warn
    given: $.paths[/books,/characters,/houses][get].responses['200'].headers
    then:
      field: Link
      function: truthy
  response-caching-headers:
    description: GET responses SHOULD include ETag, Last-Modified, and Cache-Control headers.
    severity: info
    given: $.paths[*][get].responses['200'].headers
    then:
    - field: ETag
      function: defined
    - field: Last-Modified
      function: defined
    - field: Cache-Control
      function: defined
  schema-property-camel-case:
    description: Schema property names MUST be camelCase.
    severity: warn
    given: $.components.schemas[*].properties.*~
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  schema-type-required:
    description: Every component schema MUST declare a `type`.
    severity: error
    given: '#Schema'
    then:
      field: type
      function: truthy
  schema-description-required:
    description: Every component schema MUST have a description.
    severity: warn
    given: '#Schema'
    then:
      field: description
      function: truthy
  schema-url-self-link:
    description: Resource schemas SHOULD include a `url` self-link.
    severity: info
    given: $.components.schemas[?(@.type=='object')]
    then:
      field: properties.url
      function: defined
  schema-related-resource-uri-format:
    description: Schema properties named like related-resource refs MUST use format=uri.
    severity: warn
    given: $.components.schemas[*].properties[url,father,mother,spouse,overlord,founder,currentLord,heir]
    then:
      field: format
      function: pattern
      functionOptions:
        match: ^uri$
  security-not-required:
    description: This API is unauthenticated; global `security` MUST NOT require credentials.
    severity: info
    given: $
    then:
      field: security
      function: falsy
  http-only-get:
    description: An API of Ice And Fire is read-only — only GET operations are allowed.
    severity: warn
    given: $.paths[*]
    then:
      function: pattern
      functionOptions:
        notMatch: (post|put|patch|delete)
  get-no-request-body:
    description: GET operations MUST NOT have a requestBody.
    severity: error
    given: $.paths[*][get]
    then:
      field: requestBody
      function: falsy
  no-empty-descriptions:
    description: Descriptions MUST NOT be empty strings.
    severity: warn
    given: $..description
    then:
      function: truthy
  examples-encouraged:
    description: Operations SHOULD include named examples on 200 responses.
    severity: info
    given: $.paths[*][get].responses['200'].content.application/json
    then:
      function: schema
      functionOptions:
        schema:
          anyOf:
          - required:
            - example
          - required:
            - examples
  path-params-casing:
    description: Path parameters should be snake_case (the dominant convention in this API).
    severity: warn
    given: $.paths[*].parameters[?(@.in=='path')].name
    then:
      function: casing
      functionOptions:
        type: snake
  query-params-casing:
    description: Query parameters should be snake_case (the dominant convention in this API).
    severity: info
    given: $.paths[*][get,post,put,patch,delete].parameters[?(@.in=='query')]
    then:
      field: name
      function: casing
      functionOptions:
        type: snake
  schema-names-casing:
    description: Component schema names should be PascalCase (the dominant convention in this API).
    severity: warn
    given: $.components.schemas
    then:
      field: '@key'
      function: casing
      functionOptions:
        type: pascal
  schema-properties-casing:
    description: Schema properties should be snake_case (the dominant convention in this API).
    severity: info
    given: $.components.schemas[*].properties
    then:
      field: '@key'
      function: casing
      functionOptions:
        type: snake
  error-schema-defined:
    description: A shared error schema (Error) should be defined for error payloads.
    severity: warn
    given: $.components.schemas
    then:
      field: Error
      function: truthy