The Movie Database · API Governance Rules

The Movie Database API Rules

Spectral linting rules defining API design standards and conventions for The Movie Database.

42 Rules error 16 warn 22 info 4
View Rules File View on GitHub

Rule Categories

tmdb

Rules

warn
tmdb-info-title-prefix
info.title should start with 'TMDB'.
$.info.title
error
tmdb-info-description-required
info.description is required and must be a substantive paragraph (>= 80 chars).
$.info
error
tmdb-info-version-required
info.version is required.
$.info
warn
tmdb-info-contact-required
info.contact should be defined with name and url.
$.info
warn
tmdb-info-license-required
info.license must be set (TMDB API Terms of Use).
$.info
error
tmdb-openapi-version
Spec must target OpenAPI 3.1.x.
$.openapi
error
tmdb-servers-defined
At least one server URL is required.
$.servers
error
tmdb-servers-https
Server URLs must use HTTPS.
$.servers[*].url
warn
tmdb-servers-host
Server URL should be https://api.themoviedb.org.
$.servers[*].url
error
tmdb-paths-version-prefix
Paths must start with /3/ (or /4/ for OAuth-list endpoints).
$.paths.*~
error
tmdb-paths-no-trailing-slash
Paths must not end with a trailing slash.
$.paths.*~
error
tmdb-paths-no-query-string
Paths must not contain a '?' (use parameters instead).
$.paths.*~
warn
tmdb-paths-snake-case
Path segments are snake_case alphanumerics (e.g. /watch/providers, /authentication/guest_session/new).
$.paths.*~
error
tmdb-operation-summary-required
Every operation must have a summary.
$.paths.*.[get,post,put,patch,delete]
warn
tmdb-operation-summary-tmdb-prefix
Operation summaries should start with 'TMDB '.
$.paths.*.[get,post,put,patch,delete].summary
warn
tmdb-operation-description-required
Every operation must have a description.
$.paths.*.[get,post,put,patch,delete]
error
tmdb-operation-id-required
Every operation must have an operationId.
$.paths.*.[get,post,put,patch,delete]
warn
tmdb-operation-id-kebab
operationId uses kebab-case (e.g. movie-details, account-add-favorite).
$.paths.*.[get,post,put,patch,delete].operationId
error
tmdb-operation-tags-required
Every operation must declare at least one tag.
$.paths.*.[get,post,put,patch,delete]
warn
tmdb-operation-microcks
Every operation should declare x-microcks-operation for mock-server compatibility.
$.paths.*.[get,post,put,patch,delete]
warn
tmdb-tags-defined
Global tags array must be declared so each operation tag is documented.
$
warn
tmdb-tags-description
Every global tag must have a description.
$.tags[*]
info
tmdb-tags-title-case
Tag names are Title Case (e.g. 'Movies', 'TV Series', 'Watch Providers').
$.tags[*].name
warn
tmdb-parameter-description
Parameters require a description.
$.paths.*.[get,post,put,patch,delete].parameters[*]
warn
tmdb-parameter-snake-case
Parameter names use snake_case (e.g. movie_id, language, api_key, append_to_response).
$.paths.*.[get,post,put,patch,delete].parameters[*].name
error
tmdb-parameter-schema-type
Parameter schemas must specify a type.
$.paths.*.[get,post,put,patch,delete].parameters[*]
info
tmdb-parameter-pagination
Pagination parameter is named 'page' (TMDB uses page-based pagination).
$.paths.*.[get,post,put,patch,delete].parameters[?(@.in == 'query' && (@.name == 'offset' || @.name == 'limit' || @.name == 'cursor'))]
error
tmdb-response-success
Every operation must define a 2xx success response.
$.paths.*.[get,post,put,patch,delete].responses
warn
tmdb-response-401
Operations should document a 401 response for auth failures.
$.paths.*.[get,post,put,patch,delete].responses
warn
tmdb-response-429
Operations should document 429 rate-limit responses.
$.paths.*.[get,post,put,patch,delete].responses
error
tmdb-response-json-content
Response content-type must be application/json.
$.paths.*.[get,post,put,patch,delete].responses.*.content
error
tmdb-response-description
Every response must have a description.
$.paths.*.[get,post,put,patch,delete].responses.*
warn
tmdb-schema-property-snake-case
Schema property names use snake_case (e.g. release_date, poster_path, vote_average).
$.components.schemas.*.properties.*~
info
tmdb-schema-title
Top-level schemas should declare a title.
$.components.schemas.*
warn
tmdb-schema-type
Schemas must declare a type.
$.components.schemas.*
warn
tmdb-security-global
A global security requirement should be set (bearerAuth or apiKeyAuth).
$.security
warn
tmdb-security-scheme-bearer
components.securitySchemes.bearerAuth must be declared for v4 token auth.
$.components.securitySchemes
warn
tmdb-security-scheme-apikey
components.securitySchemes.apiKeyAuth must be declared for v3 api_key auth.
$.components.securitySchemes
error
tmdb-get-no-request-body
GET operations must not declare a requestBody.
$.paths.*.get
warn
tmdb-delete-no-request-body
DELETE operations should not declare a requestBody.
$.paths.*.delete
warn
tmdb-no-empty-description
Descriptions must not be empty strings.
$..description
info
tmdb-examples-encouraged
JSON response media types should include named examples for mock-server compatibility.
$.paths.*.[get,post,put,patch,delete].responses.*.content.application/json

Spectral Ruleset

Raw ↑
# Spectral ruleset for TMDB API conventions
#
# Generated by api-evangelist. Enforces the patterns observed across the TMDB OpenAPI
# specification (v3): path-versioned, snake_case path/query/property naming, summaries
# prefixed with "TMDB", PascalCase operationIds, JSON-only responses, bearer + apiKey
# auth, and Microcks-compatible mocking conventions.
#
# Run with:
#   npx @stoplight/spectral lint -r rules/tmdb-rules.yml openapi/*.yml

extends: "spectral:oas"

rules:

  # ─────────────────────────────────────────────────────────────────────
  # INFO / METADATA
  # ─────────────────────────────────────────────────────────────────────

  tmdb-info-title-prefix:
    description: "info.title should start with 'TMDB'."
    message: "info.title should start with 'TMDB' (got '{{value}}')."
    severity: warn
    given: "$.info.title"
    then:
      function: pattern
      functionOptions:
        match: "^TMDB"

  tmdb-info-description-required:
    description: "info.description is required and must be a substantive paragraph (>= 80 chars)."
    severity: error
    given: "$.info"
    then:
      - field: description
        function: truthy
      - field: description
        function: length
        functionOptions:
          min: 80

  tmdb-info-version-required:
    description: "info.version is required."
    severity: error
    given: "$.info"
    then:
      field: version
      function: truthy

  tmdb-info-contact-required:
    description: "info.contact should be defined with name and url."
    severity: warn
    given: "$.info"
    then:
      - field: contact
        function: truthy
      - field: contact.url
        function: truthy

  tmdb-info-license-required:
    description: "info.license must be set (TMDB API Terms of Use)."
    severity: warn
    given: "$.info"
    then:
      field: license.url
      function: truthy

  # ─────────────────────────────────────────────────────────────────────
  # OPENAPI VERSION
  # ─────────────────────────────────────────────────────────────────────

  tmdb-openapi-version:
    description: "Spec must target OpenAPI 3.1.x."
    severity: error
    given: "$.openapi"
    then:
      function: pattern
      functionOptions:
        match: "^3\\.1\\."

  # ─────────────────────────────────────────────────────────────────────
  # SERVERS
  # ─────────────────────────────────────────────────────────────────────

  tmdb-servers-defined:
    description: "At least one server URL is required."
    severity: error
    given: "$.servers"
    then:
      function: length
      functionOptions:
        min: 1

  tmdb-servers-https:
    description: "Server URLs must use HTTPS."
    severity: error
    given: "$.servers[*].url"
    then:
      function: pattern
      functionOptions:
        match: "^https://"

  tmdb-servers-host:
    description: "Server URL should be https://api.themoviedb.org."
    severity: warn
    given: "$.servers[*].url"
    then:
      function: pattern
      functionOptions:
        match: "^https://api\\.themoviedb\\.org"

  # ─────────────────────────────────────────────────────────────────────
  # PATHS — NAMING CONVENTIONS
  # ─────────────────────────────────────────────────────────────────────

  tmdb-paths-version-prefix:
    description: "Paths must start with /3/ (or /4/ for OAuth-list endpoints)."
    severity: error
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        match: "^/(3|4)/"

  tmdb-paths-no-trailing-slash:
    description: "Paths must not end with a trailing slash."
    severity: error
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        notMatch: ".+/$"

  tmdb-paths-no-query-string:
    description: "Paths must not contain a '?' (use parameters instead)."
    severity: error
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        notMatch: "\\?"

  tmdb-paths-snake-case:
    description: "Path segments are snake_case alphanumerics (e.g. /watch/providers, /authentication/guest_session/new)."
    severity: warn
    given: "$.paths.*~"
    then:
      function: pattern
      functionOptions:
        match: "^(/(3|4))(/[a-z0-9_]+|/\\{[a-z_]+\\})*$"

  # ─────────────────────────────────────────────────────────────────────
  # OPERATIONS
  # ─────────────────────────────────────────────────────────────────────

  tmdb-operation-summary-required:
    description: "Every operation must have a summary."
    severity: error
    given: "$.paths.*.[get,post,put,patch,delete]"
    then:
      field: summary
      function: truthy

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

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

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

  tmdb-operation-id-kebab:
    description: "operationId uses kebab-case (e.g. movie-details, account-add-favorite)."
    severity: warn
    given: "$.paths.*.[get,post,put,patch,delete].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-z0-9-]*$"

  tmdb-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: length
      functionOptions:
        min: 1

  tmdb-operation-microcks:
    description: "Every operation should declare x-microcks-operation for mock-server compatibility."
    severity: warn
    given: "$.paths.*.[get,post,put,patch,delete]"
    then:
      field: x-microcks-operation
      function: truthy

  # ─────────────────────────────────────────────────────────────────────
  # TAGS
  # ─────────────────────────────────────────────────────────────────────

  tmdb-tags-defined:
    description: "Global tags array must be declared so each operation tag is documented."
    severity: warn
    given: "$"
    then:
      field: tags
      function: length
      functionOptions:
        min: 1

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

  tmdb-tags-title-case:
    description: "Tag names are Title Case (e.g. 'Movies', 'TV Series', 'Watch Providers')."
    severity: info
    given: "$.tags[*].name"
    then:
      function: pattern
      functionOptions:
        match: "^[A-Z][A-Za-z]+( [A-Z][A-Za-z]+)*$"

  # ─────────────────────────────────────────────────────────────────────
  # PARAMETERS
  # ─────────────────────────────────────────────────────────────────────

  tmdb-parameter-description:
    description: "Parameters require a description."
    severity: warn
    given: "$.paths.*.[get,post,put,patch,delete].parameters[*]"
    then:
      field: description
      function: truthy

  tmdb-parameter-snake-case:
    description: "Parameter names use snake_case (e.g. movie_id, language, api_key, append_to_response)."
    severity: warn
    given: "$.paths.*.[get,post,put,patch,delete].parameters[*].name"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-z0-9_]*$"

  tmdb-parameter-schema-type:
    description: "Parameter schemas must specify a type."
    severity: error
    given: "$.paths.*.[get,post,put,patch,delete].parameters[*]"
    then:
      field: schema.type
      function: truthy

  tmdb-parameter-pagination:
    description: "Pagination parameter is named 'page' (TMDB uses page-based pagination)."
    severity: info
    given: "$.paths.*.[get,post,put,patch,delete].parameters[?(@.in == 'query' && (@.name == 'offset' || @.name == 'limit' || @.name == 'cursor'))]"
    then:
      function: falsy

  # ─────────────────────────────────────────────────────────────────────
  # RESPONSES
  # ─────────────────────────────────────────────────────────────────────

  tmdb-response-success:
    description: "Every operation must define a 2xx success response."
    severity: error
    given: "$.paths.*.[get,post,put,patch,delete].responses"
    then:
      function: pattern
      functionOptions:
        match: "2\\d\\d"

  tmdb-response-401:
    description: "Operations should document a 401 response for auth failures."
    severity: warn
    given: "$.paths.*.[get,post,put,patch,delete].responses"
    then:
      field: "401"
      function: truthy

  tmdb-response-429:
    description: "Operations should document 429 rate-limit responses."
    severity: warn
    given: "$.paths.*.[get,post,put,patch,delete].responses"
    then:
      field: "429"
      function: truthy

  tmdb-response-json-content:
    description: "Response content-type must be application/json."
    severity: error
    given: "$.paths.*.[get,post,put,patch,delete].responses.*.content"
    then:
      field: "application/json"
      function: truthy

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

  # ─────────────────────────────────────────────────────────────────────
  # SCHEMAS — PROPERTY NAMING
  # ─────────────────────────────────────────────────────────────────────

  tmdb-schema-property-snake-case:
    description: "Schema property names use snake_case (e.g. release_date, poster_path, vote_average)."
    severity: warn
    given: "$.components.schemas.*.properties.*~"
    then:
      function: pattern
      functionOptions:
        match: "^[a-z][a-z0-9_]*$"

  tmdb-schema-title:
    description: "Top-level schemas should declare a title."
    severity: info
    given: "$.components.schemas.*"
    then:
      field: title
      function: truthy

  tmdb-schema-type:
    description: "Schemas must declare a type."
    severity: warn
    given: "$.components.schemas.*"
    then:
      field: type
      function: truthy

  # ─────────────────────────────────────────────────────────────────────
  # SECURITY
  # ─────────────────────────────────────────────────────────────────────

  tmdb-security-global:
    description: "A global security requirement should be set (bearerAuth or apiKeyAuth)."
    severity: warn
    given: "$.security"
    then:
      function: length
      functionOptions:
        min: 1

  tmdb-security-scheme-bearer:
    description: "components.securitySchemes.bearerAuth must be declared for v4 token auth."
    severity: warn
    given: "$.components.securitySchemes"
    then:
      field: bearerAuth
      function: truthy

  tmdb-security-scheme-apikey:
    description: "components.securitySchemes.apiKeyAuth must be declared for v3 api_key auth."
    severity: warn
    given: "$.components.securitySchemes"
    then:
      field: apiKeyAuth
      function: truthy

  # ─────────────────────────────────────────────────────────────────────
  # HTTP METHOD CONVENTIONS
  # ─────────────────────────────────────────────────────────────────────

  tmdb-get-no-request-body:
    description: "GET operations must not declare a requestBody."
    severity: error
    given: "$.paths.*.get"
    then:
      field: requestBody
      function: falsy

  tmdb-delete-no-request-body:
    description: "DELETE operations should not declare a requestBody."
    severity: warn
    given: "$.paths.*.delete"
    then:
      field: requestBody
      function: falsy

  # ─────────────────────────────────────────────────────────────────────
  # GENERAL QUALITY
  # ─────────────────────────────────────────────────────────────────────

  tmdb-no-empty-description:
    description: "Descriptions must not be empty strings."
    severity: warn
    given: "$..description"
    then:
      function: pattern
      functionOptions:
        notMatch: "^$"

  tmdb-examples-encouraged:
    description: "JSON response media types should include named examples for mock-server compatibility."
    severity: info
    given: "$.paths.*.[get,post,put,patch,delete].responses.*.content.application/json"
    then:
      field: examples
      function: truthy