Ternary · API Governance Rules

Ternary API Rules

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

23 Rules error 7 warn 14
View Rules File View on GitHub

Rule Categories

ternary

Rules

false
ternary-security-defined
All Ternary API operations must require authentication
$.paths[*][get,post,put,patch,delete]
error
ternary-global-security
Global security must be defined for Ternary API
$
error
ternary-path-versioned
All Ternary API paths must start with /v1/
$.paths[*]~
warn
ternary-path-kebab-case
Path segments must use kebab-case
$.paths[*]~
false
ternary-collection-plural-nouns
Collection endpoints should use plural nouns
$.paths[*]~
warn
ternary-list-uses-get
List operations must use GET method
$.paths[*][get].operationId
warn
ternary-create-uses-post
Create operations should use POST
$.paths[*][post].operationId
warn
ternary-update-uses-put
Update operations should use PUT
$.paths[*][put].operationId
error
ternary-delete-uses-delete
Delete operations must use DELETE
$.paths[*][delete].operationId
error
ternary-list-response-200
List and GET operations must return 200
$.paths[*][get].responses
warn
ternary-create-response-201
Create operations should return 201
$.paths[*][post].responses
warn
ternary-delete-response-204
Delete operations should return 204
$.paths[*][delete].responses
error
ternary-401-defined
All operations must define a 401 Unauthorized response
$.paths[*][get,post,put,patch,delete].responses
warn
ternary-404-for-resource-ops
Operations with path parameters should define 404
$.paths[*~'/{[^}]+}'][get,put,delete].responses
warn
ternary-pagination-params
List endpoints should support pagination parameters
$.paths[*][get][?(@.operationId && @.operationId.startsWith('list'))]
error
ternary-operation-summary
All operations must have a summary
$.paths[*][get,post,put,patch,delete]
warn
ternary-summary-title-case
Operation summaries must use Title Case
$.paths[*][get,post,put,patch,delete].summary
warn
ternary-operation-description
All operations should have a description
$.paths[*][get,post,put,patch,delete]
error
ternary-tags-defined
All operations must have tags
$.paths[*][get,post,put,patch,delete]
warn
ternary-schema-description
Schema objects should have descriptions
$.components.schemas[*]
warn
ternary-no-inline-schemas
Prefer reusable schemas in components over inline definitions
$.paths[*][*].responses[*].content[*].schema
warn
ternary-cost-fields-numeric
Cost and amount fields should be numeric type
$.components.schemas[*].properties[?(@key =~ /cost|amount|spend|budget/i)]
warn
ternary-date-fields-format
Date fields should use ISO 8601 format
$.components.schemas[*].properties[?(@key =~ /date|_at$/i)]

Spectral Ruleset

Raw ↑
extends: spectral:oas
rules:
  # API Key Security
  ternary-security-defined:
    description: All Ternary API operations must require authentication
    message: "Operation '{{path}}' must require API key authentication"
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: security
      function: truthy
    severity: off

  ternary-global-security:
    description: Global security must be defined for Ternary API
    message: "Ternary API must define global security with API key"
    given: "$"
    then:
      field: security
      function: truthy
    severity: error

  # Versioning
  ternary-path-versioned:
    description: All Ternary API paths must start with /v1/
    message: "Path '{{property}}' must start with /v1/"
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        match: "^/v1/"
    severity: error

  # Path Conventions
  ternary-path-kebab-case:
    description: Path segments must use kebab-case
    message: "Path segment in '{{property}}' must use kebab-case"
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        match: "^(/v1/[a-z0-9-/{}_]+)$"
    severity: warn

  ternary-collection-plural-nouns:
    description: Collection endpoints should use plural nouns
    message: "Collection path should use plural nouns"
    given: "$.paths[*]~"
    then:
      function: pattern
      functionOptions:
        notMatch: "^/v1/[a-z]+-[a-z]+$"
    severity: off

  # HTTP Methods
  ternary-list-uses-get:
    description: List operations must use GET method
    message: "List operations should use GET, not POST"
    given: "$.paths[*][get].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^(list|get)[A-Z]"
    severity: warn

  ternary-create-uses-post:
    description: Create operations should use POST
    message: "Create operations should use POST"
    given: "$.paths[*][post].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^(create|trigger|run|acknowledge)[A-Z]"
    severity: warn

  ternary-update-uses-put:
    description: Update operations should use PUT
    message: "Full update operations should use PUT"
    given: "$.paths[*][put].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^update[A-Z]"
    severity: warn

  ternary-delete-uses-delete:
    description: Delete operations must use DELETE
    message: "Delete operations must use DELETE method"
    given: "$.paths[*][delete].operationId"
    then:
      function: pattern
      functionOptions:
        match: "^delete[A-Z]"
    severity: error

  # Response Codes
  ternary-list-response-200:
    description: List and GET operations must return 200
    message: "GET operation must define a 200 response"
    given: "$.paths[*][get].responses"
    then:
      field: "200"
      function: truthy
    severity: error

  ternary-create-response-201:
    description: Create operations should return 201
    message: "POST create operations should return 201 Created"
    given: "$.paths[*][post].responses"
    then:
      field: "201"
      function: truthy
    severity: warn

  ternary-delete-response-204:
    description: Delete operations should return 204
    message: "DELETE operations should return 204 No Content"
    given: "$.paths[*][delete].responses"
    then:
      field: "204"
      function: truthy
    severity: warn

  ternary-401-defined:
    description: All operations must define a 401 Unauthorized response
    message: "Operation must define a 401 Unauthorized response"
    given: "$.paths[*][get,post,put,patch,delete].responses"
    then:
      field: "401"
      function: truthy
    severity: error

  ternary-404-for-resource-ops:
    description: Operations with path parameters should define 404
    message: "Resource operations with path parameters should define 404 Not Found"
    given: "$.paths[*~'/{[^}]+}'][get,put,delete].responses"
    then:
      field: "404"
      function: truthy
    severity: warn

  # Pagination
  ternary-pagination-params:
    description: List endpoints should support pagination parameters
    message: "List endpoint should include page_token and page_size query parameters"
    given: "$.paths[*][get][?(@.operationId && @.operationId.startsWith('list'))]"
    then:
      field: parameters
      function: truthy
    severity: warn

  # Documentation
  ternary-operation-summary:
    description: All operations must have a summary
    message: "Operation '{{path}}' is missing a summary"
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: summary
      function: truthy
    severity: error

  ternary-summary-title-case:
    description: Operation summaries must use Title Case
    message: "Summary '{{value}}' must start with a capital letter (Title Case)"
    given: "$.paths[*][get,post,put,patch,delete].summary"
    then:
      function: pattern
      functionOptions:
        match: "^[A-Z]"
    severity: warn

  ternary-operation-description:
    description: All operations should have a description
    message: "Operation is missing a description"
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: description
      function: truthy
    severity: warn

  ternary-tags-defined:
    description: All operations must have tags
    message: "Operation is missing tags"
    given: "$.paths[*][get,post,put,patch,delete]"
    then:
      field: tags
      function: truthy
    severity: error

  # Schema Quality
  ternary-schema-description:
    description: Schema objects should have descriptions
    message: "Schema component '{{path}}' is missing a description"
    given: "$.components.schemas[*]"
    then:
      field: description
      function: truthy
    severity: warn

  ternary-no-inline-schemas:
    description: Prefer reusable schemas in components over inline definitions
    message: "Use $ref to reusable schemas instead of inline definitions"
    given: "$.paths[*][*].responses[*].content[*].schema"
    then:
      field: "$ref"
      function: truthy
    severity: warn

  # FinOps Domain Conventions
  ternary-cost-fields-numeric:
    description: Cost and amount fields should be numeric type
    message: "Cost/amount field should be type: number"
    given: "$.components.schemas[*].properties[?(@key =~ /cost|amount|spend|budget/i)]"
    then:
      field: type
      function: enumeration
      functionOptions:
        values:
          - number
          - integer
    severity: warn

  ternary-date-fields-format:
    description: Date fields should use ISO 8601 format
    message: "Date field should have format: date or format: date-time"
    given: "$.components.schemas[*].properties[?(@key =~ /date|_at$/i)]"
    then:
      field: format
      function: truthy
    severity: warn