SWAPI - Star Wars API · API Governance Rules

SWAPI - Star Wars API API Rules

Spectral linting rules defining API design standards and conventions for SWAPI - Star Wars API.

39 Rules error 10 warn 24 info 5
Generated by API Evangelist Written by API Evangelist tooling for SWAPI - Star Wars API's APIs. It is a starting point, not a ruleset SWAPI - Star Wars API publishes or enforces.
View Rules File View on GitHub

Rule Categories

error external get info no openapi operation parameter path paths query response schema servers tag

Rules

warn
info-title-swapi-prefix
API title MUST begin with "SWAPI".
$.info.title
warn
info-description-required
API description MUST be present and non-trivial.
$.info
error
info-version-required
API version MUST be defined.
$.info
info
info-contact-required
A contact block (community channel) MUST be defined.
$.info
warn
info-license-required
A license SHOULD be declared (SWAPI is open source).
$.info
warn
openapi-version-3-0-x
OpenAPI version MUST be 3.0.x.
$.openapi
error
servers-defined
At least one server entry MUST be defined.
$.servers
error
servers-https
Every server URL MUST use HTTPS.
$.servers[*].url
warn
servers-have-description
Each server entry SHOULD have a description.
$.servers[*]
error
paths-lowercase
Path segments MUST be lowercase.
$.paths.*~
info
paths-plural-resources
Top-level resource collections SHOULD use plural nouns (films, people, planets, species, starships, vehicles).
$.paths.*~
error
paths-no-query-string
Paths MUST NOT include query strings.
$.paths.*~
error
operation-operationid-required
Every operation MUST have an operationId.
$.paths[*][get,post,put,patch,delete,head,options]
warn
operation-operationid-camelcase
operationId MUST be camelCase.
$.paths[*][get,post,put,patch,delete,head,options].operationId
error
operation-summary-required
Every operation MUST have a summary.
$.paths[*][get,post,put,patch,delete,head,options]
warn
operation-summary-title-case
Operation summaries SHOULD use Title Case.
$.paths[*][get,post,put,patch,delete,head,options].summary
warn
operation-description-required
Every operation MUST have a description.
$.paths[*][get,post,put,patch,delete,head,options]
error
operation-tags-required
Every operation MUST be tagged.
$.paths[*][get,post,put,patch,delete,head,options]
warn
tag-global-defined
Tags MUST be defined at the document root.
$
warn
tag-description-required
Each global tag SHOULD have a description.
$.tags[*]
warn
tag-title-case
Tag names MUST use Title Case.
$.tags[*].name
warn
parameter-description-required
Every parameter MUST have a description.
$.paths[*][*].parameters[*]
warn
parameter-snake-case
Parameter names SHOULD be snake_case (SWAPI convention is single-word lowercase, e.g. `search`, `page`, `id`).
$.paths[*][*].parameters[*].name
info
parameter-pagination-page
Pagination parameter MUST be named `page` (SWAPI convention).
$.paths[*][*].parameters[?(@.in=='query' && (@.name=='offset' || @.name=='limit' || @.name=='cursor'))]
error
response-success-required
Every operation MUST declare a 2xx response.
$.paths[*][*].responses
warn
response-404-required
GET operations on resource detail paths MUST declare a 404 response.
$.paths[?(@property.match(/\{id\}/))][get].responses
warn
response-description-required
Every response MUST have a description.
$.paths[*][*].responses[*]
warn
response-content-json
Responses with content SHOULD use application/json.
$.paths[*][*].responses[*].content
warn
schema-property-snake-case
Schema property names MUST be snake_case (the SWAPI wire format convention).
$.components.schemas[*].properties.*~
warn
schema-types-defined
Schema properties MUST declare a `type`.
$.components.schemas[*].properties[*]
info
schema-canonical-fields
Resource schemas MUST include `created`, `edited`, and `url` (SWAPI canonical envelope fields).
$.components.schemas[?(@property=='Film' || @property=='Person' || @property=='Planet' || @property=='Species' || @property=='Starship' || @property=='Vehicle')].properties
error
get-no-request-body
GET operations MUST NOT have a request body.
$.paths[*].get
warn
no-empty-descriptions
Descriptions MUST NOT be empty.
$..description
info
external-docs-encouraged
Top-level externalDocs SHOULD be defined.
$
warn
path-params-casing
Path parameters should be snake_case (the dominant convention in this API).
$.paths[*].parameters[?(@.in=='path')].name
warn
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
warn
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 ↑
# authorship: generated by API Evangelist tooling. Stamped 2026-08-18
# on the file's own generator header (roadmap#64). An unmarked file is
# NOT assumed to be ours -- absence of evidence was never stamped.
x-method: generated
# swapi — 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)
#   - path-params-casing: snake @ 100% (n=6)
#   - query-params-casing: snake @ 100% (n=12)
#   - operationid-casing: camel @ 100% (n=12)
#   - schema-names-casing: pascal @ 100% (n=14)
#   - schema-properties-casing: snake @ 99% (n=97)
#   - error-schema-defined: Error
#   - operation-documents-404: 100% adherence
#   - pagination params observed: ['page']
#   - merge: kept 34 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-swapi-prefix:
    description: API title MUST begin with "SWAPI".
    message: '{{property}} must start with ''SWAPI'' (e.g. ''SWAPI - Star Wars API'').'
    severity: warn
    given: $.info.title
    then:
      function: pattern
      functionOptions:
        match: ^SWAPI
  info-description-required:
    description: API description MUST be present and non-trivial.
    message: '{{property}} description is required (min 30 chars).'
    severity: warn
    given: $.info
    then:
    - field: description
      function: truthy
    - field: description
      function: length
      functionOptions:
        min: 30
  info-version-required:
    description: API version MUST be defined.
    severity: error
    given: $.info
    then:
      field: version
      function: truthy
  info-contact-required:
    description: A contact block (community channel) MUST be defined.
    severity: info
    given: $.info
    then:
      field: contact
      function: truthy
  info-license-required:
    description: A license SHOULD be declared (SWAPI is open source).
    severity: warn
    given: $.info
    then:
      field: license
      function: truthy
  openapi-version-3-0-x:
    description: OpenAPI version MUST be 3.0.x.
    severity: warn
    given: $.openapi
    then:
      function: pattern
      functionOptions:
        match: ^3\.0\.
  servers-defined:
    description: At least one server entry MUST be defined.
    severity: error
    given: $.servers
    then:
      function: truthy
  servers-https:
    description: Every server URL MUST use HTTPS.
    severity: error
    given: $.servers[*].url
    then:
      function: pattern
      functionOptions:
        match: ^https://
  servers-have-description:
    description: Each server entry SHOULD have a description.
    severity: warn
    given: $.servers[*]
    then:
      field: description
      function: truthy
  paths-lowercase:
    description: Path segments MUST be lowercase.
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: ^/[a-z0-9/{}_-]*$
  paths-plural-resources:
    description: Top-level resource collections SHOULD use plural nouns (films, people, planets, species,
      starships, vehicles).
    severity: info
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        match: ^/(films|people|planets|species|starships|vehicles)(/|/\{id\}/)?$
  paths-no-query-string:
    description: Paths MUST NOT include query strings.
    severity: error
    given: $.paths.*~
    then:
      function: pattern
      functionOptions:
        notMatch: \?
  operation-operationid-required:
    description: Every operation MUST have an operationId.
    severity: error
    given: $.paths[*][get,post,put,patch,delete,head,options]
    then:
      field: operationId
      function: truthy
  operation-operationid-camelcase:
    description: operationId MUST be camelCase.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete,head,options].operationId
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-zA-Z0-9]*$
  operation-summary-required:
    description: Every operation MUST have a summary.
    severity: error
    given: $.paths[*][get,post,put,patch,delete,head,options]
    then:
      field: summary
      function: truthy
  operation-summary-title-case:
    description: Operation summaries SHOULD use Title Case.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete,head,options].summary
    then:
      function: pattern
      functionOptions:
        match: ^[A-Z][A-Za-z0-9 -]*$
  operation-description-required:
    description: Every operation MUST have a description.
    severity: warn
    given: $.paths[*][get,post,put,patch,delete,head,options]
    then:
      field: description
      function: truthy
  operation-tags-required:
    description: Every operation MUST be tagged.
    severity: error
    given: $.paths[*][get,post,put,patch,delete,head,options]
    then:
      field: tags
      function: truthy
  tag-global-defined:
    description: Tags MUST be defined at the document root.
    severity: warn
    given: $
    then:
      field: tags
      function: truthy
  tag-description-required:
    description: Each global tag SHOULD have a description.
    severity: warn
    given: $.tags[*]
    then:
      field: description
      function: truthy
  tag-title-case:
    description: Tag names MUST use Title Case.
    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: $.paths[*][*].parameters[*]
    then:
      field: description
      function: truthy
  parameter-snake-case:
    description: Parameter names SHOULD be snake_case (SWAPI convention is single-word lowercase, e.g.
      `search`, `page`, `id`).
    severity: warn
    given: $.paths[*][*].parameters[*].name
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-z0-9_]*$
  parameter-pagination-page:
    description: Pagination parameter MUST be named `page` (SWAPI convention).
    severity: info
    given: $.paths[*][*].parameters[?(@.in=='query' && (@.name=='offset' || @.name=='limit' || @.name=='cursor'))]
    then:
      function: falsy
  response-success-required:
    description: Every operation MUST declare a 2xx response.
    severity: error
    given: $.paths[*][*].responses
    then:
      field: '200'
      function: truthy
  response-404-required:
    description: GET operations on resource detail paths MUST declare a 404 response.
    severity: warn
    given: $.paths[?(@property.match(/\{id\}/))][get].responses
    then:
      field: '404'
      function: truthy
  response-description-required:
    description: Every response MUST have a description.
    severity: warn
    given: $.paths[*][*].responses[*]
    then:
      field: description
      function: truthy
  response-content-json:
    description: Responses with content SHOULD use application/json.
    severity: warn
    given: $.paths[*][*].responses[*].content
    then:
      field: application/json
      function: truthy
  schema-property-snake-case:
    description: Schema property names MUST be snake_case (the SWAPI wire format convention).
    severity: warn
    given: $.components.schemas[*].properties.*~
    then:
      function: pattern
      functionOptions:
        match: ^[a-z][a-z0-9_]*$|^[A-Z]+$
  schema-types-defined:
    description: Schema properties MUST declare a `type`.
    severity: warn
    given: $.components.schemas[*].properties[*]
    then:
      field: type
      function: truthy
  schema-canonical-fields:
    description: Resource schemas MUST include `created`, `edited`, and `url` (SWAPI canonical envelope
      fields).
    severity: info
    given: $.components.schemas[?(@property=='Film' || @property=='Person' || @property=='Planet' || @property=='Species'
      || @property=='Starship' || @property=='Vehicle')].properties
    then:
    - field: created
      function: truthy
    - field: edited
      function: truthy
    - field: url
      function: truthy
  get-no-request-body:
    description: GET operations MUST NOT have a request body.
    severity: error
    given: $.paths[*].get
    then:
      field: requestBody
      function: falsy
  no-empty-descriptions:
    description: Descriptions MUST NOT be empty.
    severity: warn
    given: $..description
    then:
      function: truthy
  external-docs-encouraged:
    description: Top-level externalDocs SHOULD be defined.
    severity: info
    given: $
    then:
      field: externalDocs
      function: truthy
  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: warn
    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: warn
    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

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/swapi-spectral-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.