# airwallex — 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: 2/2 servers on airwallex.com
# - path-params-casing: snake @ 100% (n=9)
# - operationid-casing: camel @ 94% (n=18)
# - security: global (root) — NOT emitting operation-security-required
# - merge: kept 29 existing, added 3 measured, upgraded 0
# - added: servers-expected-domain, path-params-casing, no-empty-descriptions
extends:
- spectral:oas
rules:
airwallex-payment-intent-required-fields:
description: Payment intent must include id, amount, currency, and status.
message: 'Payment intent object is missing required field: {{property}}'
severity: error
given: $.components.schemas.PaymentIntent.required
then:
function: schema
functionOptions:
schema:
type: array
contains:
type: string
enum:
- id
- amount
- currency
- status
airwallex-transfer-required-fields:
description: Transfer object must include id, source_amount, source_currency, and status.
message: 'Transfer object is missing required field: {{property}}'
severity: error
given: $.components.schemas.Transfer.required
then:
function: schema
functionOptions:
schema:
type: array
contains:
type: string
enum:
- id
- source_amount
- source_currency
- status
airwallex-operation-summary-exists:
description: Every API operation must have a non-empty summary.
message: 'Operation is missing a summary: {{path}}'
severity: error
given: $.paths[*][get,post,put,patch,delete]
then:
field: summary
function: truthy
airwallex-operation-summary-title-case:
description: Operation summaries must be in Title Case.
message: 'Operation summary should be in Title Case: {{value}}'
severity: warn
given: $.paths[*][get,post,put,patch,delete].summary
then:
function: pattern
functionOptions:
match: ^[A-Z][a-zA-Z0-9]*([ ][A-Z][a-zA-Z0-9]*)*$
airwallex-operation-description-exists:
description: Every API operation should have a description.
message: 'Operation is missing a description: {{path}}'
severity: warn
given: $.paths[*][get,post,put,patch,delete]
then:
field: description
function: truthy
airwallex-operation-tags-exist:
description: Every operation must be tagged for grouping and documentation.
message: 'Operation must have at least one tag: {{path}}'
severity: error
given: $.paths[*][get,post,put,patch,delete]
then:
field: tags
function: truthy
airwallex-operation-id-exists:
description: Every operation must have a unique operationId.
message: 'Operation is missing an operationId: {{path}}'
severity: error
given: $.paths[*][get,post,put,patch,delete]
then:
field: operationId
function: truthy
airwallex-operation-id-camel-case:
description: operationId must be in camelCase format.
message: 'operationId should be camelCase: {{value}}'
severity: warn
given: $.paths[*][get,post,put,patch,delete].operationId
then:
function: pattern
functionOptions:
match: ^[a-z][a-zA-Z0-9]*$
airwallex-response-200-exists:
description: Every GET operation must define a 200 success response.
message: 'GET operation must define a 200 response: {{path}}'
severity: error
given: $.paths[*].get
then:
field: responses.200
function: truthy
airwallex-response-400-documented:
description: Operations accepting request bodies should document 400 errors.
message: 'POST/PUT operation should document 400 error response: {{path}}'
severity: warn
given: $.paths[*][post,put]
then:
field: responses.400
function: truthy
airwallex-currency-iso4217-format:
description: Currency fields must be ISO 4217 three-letter uppercase codes.
message: 'Currency field should match ISO 4217 format (e.g., USD, GBP): {{path}}'
severity: warn
given: $.components.schemas[*].properties[*currency*]
then:
field: pattern
function: truthy
airwallex-amount-type-number:
description: Amount fields must be typed as number.
message: 'Amount field should be of type ''number'': {{path}}'
severity: warn
given: $.components.schemas[*].properties[*amount*]
then:
field: type
function: enumeration
functionOptions:
values:
- number
airwallex-status-enum-defined:
description: Status fields must use an enum of allowed values.
message: 'Status field should define allowed enum values: {{path}}'
severity: warn
given: $.components.schemas[*].properties.status
then:
field: enum
function: truthy
airwallex-schema-description-exists:
description: All schema components must include a description.
message: 'Schema is missing a description: {{path}}'
severity: warn
given: $.components.schemas[*]
then:
field: description
function: truthy
airwallex-property-description-exists:
description: All schema properties should include descriptions.
message: 'Property is missing a description: {{path}}'
severity: info
given: $.components.schemas[*].properties[*]
then:
field: description
function: truthy
airwallex-datetime-format:
description: Timestamp fields must use date-time format.
message: 'Timestamp field should specify format: date-time: {{path}}'
severity: warn
given: $.components.schemas[*].properties[*_at]
then:
field: format
function: enumeration
functionOptions:
values:
- date-time
airwallex-microcks-operation-extension:
description: All operations should include x-microcks-operation for mock support.
message: 'Operation is missing x-microcks-operation extension: {{path}}'
severity: info
given: $.paths[*][get,post,put,patch,delete]
then:
field: x-microcks-operation
function: truthy
airwallex-security-defined:
description: API must define security schemes for authentication.
message: API is missing security scheme definitions.
severity: error
given: $
then:
field: components.securitySchemes
function: truthy
airwallex-bearer-auth-scheme:
description: Airwallex APIs must use Bearer token authentication.
message: API should define a Bearer authentication scheme.
severity: warn
given: $.components.securitySchemes[*]
then:
field: scheme
function: enumeration
functionOptions:
values:
- bearer
airwallex-path-lowercase:
description: API paths must be lowercase and use hyphens for word separation.
message: 'Path should be lowercase with hyphens: {{path}}'
severity: warn
given: $.paths[*]~
then:
function: pattern
functionOptions:
match: ^(/[a-z0-9{}_-]+)+$
airwallex-no-trailing-slash:
description: API paths must not end with a trailing slash.
message: 'Path must not end with a trailing slash: {{path}}'
severity: warn
given: $.paths[*]~
then:
function: pattern
functionOptions:
notMatch: /$
airwallex-info-title-exists:
description: API info block must include a title.
message: API info is missing a title.
severity: error
given: $.info
then:
field: title
function: truthy
airwallex-info-version-exists:
description: API info block must include a version.
message: API info is missing a version.
severity: error
given: $.info
then:
field: version
function: truthy
airwallex-info-description-exists:
description: API info block should include a description.
message: API info is missing a description.
severity: warn
given: $.info
then:
field: description
function: truthy
airwallex-contact-info-exists:
description: API info should include contact information.
message: API info is missing contact details.
severity: info
given: $.info
then:
field: contact
function: truthy
airwallex-servers-defined:
description: API must define at least one server URL.
message: API is missing server definitions.
severity: error
given: $
then:
field: servers
function: truthy
airwallex-server-https:
description: All server URLs must use HTTPS.
message: 'Server URL must use HTTPS: {{value}}'
severity: error
given: $.servers[*].url
then:
function: pattern
functionOptions:
match: ^https://
airwallex-pagination-limit-param:
description: List endpoints should support a limit query parameter.
message: 'List endpoint should accept a limit query parameter: {{path}}'
severity: info
given: $.paths[*].get.parameters[*][?(@.in == 'query' && @.name == 'limit')]
then:
field: name
function: truthy
airwallex-request-body-content-type:
description: Request bodies must specify application/json content type.
message: 'Request body should specify application/json content type: {{path}}'
severity: warn
given: $.paths[*][post,put,patch].requestBody.content
then:
field: application/json
function: truthy
servers-expected-domain:
description: Server URLs should be on the airwallex.com domain.
severity: warn
given: $.servers[*].url
then:
function: pattern
functionOptions:
match: airwallex\.com
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
no-empty-descriptions:
description: Descriptions must not be empty strings.
severity: warn
given: $..description
then:
function: truthy