diff --git a/.spectral.yaml b/.spectral.yaml index 4121409..bc702ce 100644 --- a/.spectral.yaml +++ b/.spectral.yaml @@ -10,3 +10,15 @@ rules: # past `null` values in examples ("Cannot read properties of null"). duplicated-entry-in-enum: off + # OpenAPI 3.1 schemas are JSON Schema 2020-12, which has no `nullable`: a schema that + # still carries the 3.0 keyword rejects null without any warning. + no-nullable-keyword: + message: "`nullable` is ignored since OpenAPI 3.1: add 'null' to the type instead, e.g. type: [string, 'null']" + severity: error + # oas3 rather than [oas3.1, oas3.2]: spectral-formats before 1.9.0 has no oas3.2 and won't load the ruleset. + formats: [oas3] + # Unresolved, so a `nullable` next to a `$ref` is reported too instead of vanishing with the resolved ref. + resolved: false + given: $..nullable + then: + function: undefined diff --git a/specs/account-management.openapi.yml b/specs/account-management.openapi.yml index 51d2e71..3813c70 100644 --- a/specs/account-management.openapi.yml +++ b/specs/account-management.openapi.yml @@ -1632,9 +1632,8 @@ paths: type: object properties: expires_at: - type: string + type: [string, 'null'] format: date-time - nullable: true description: |- When the new token expires (ISO 8601 date-time, must be in the future). Must be no more than 5 years in the future. @@ -2402,9 +2401,9 @@ components: type: string description: The token value with all but the last characters masked expires_at: - type: string + type: [string, 'null'] format: date-time - description: Api token expiration time + description: Api token expiration time; null if the token does not expire description: Entity that has permissions to the resources type: object resources: @@ -2533,9 +2532,8 @@ components: type: string description: Name of the user or token that created this token expires_at: - type: string + type: [string, 'null'] format: date-time - nullable: true description: When the token expires (ISO 8601); null if the token does not expire resources: type: array @@ -2569,9 +2567,8 @@ components: type: string description: Name of the user or token that created this token expires_at: - type: string + type: [string, 'null'] format: date-time - nullable: true description: When the token expires (ISO 8601); null if the token does not expire resources: type: array @@ -2626,9 +2623,8 @@ components: maxLength: 100 description: Display name for the token expires_at: - type: string + type: [string, 'null'] format: date-time - nullable: true description: |- When the token expires (ISO 8601 date-time, must be in the future). Must be no more than 5 years in the future. diff --git a/specs/contacts.openapi.yml b/specs/contacts.openapi.yml index 0aecc0a..58e4545 100644 --- a/specs/contacts.openapi.yml +++ b/specs/contacts.openapi.yml @@ -3063,8 +3063,7 @@ components: maxLength: 255 additionalProperties: oneOf: - - type: string - nullable: true + - type: [string, 'null'] - type: number - type: boolean example: @@ -3092,8 +3091,7 @@ components: maxLength: 255 additionalProperties: oneOf: - - type: string - nullable: true + - type: [string, 'null'] - type: number - type: boolean example: @@ -3123,8 +3121,7 @@ components: type: string format: date-time url: - type: string - nullable: true + type: [string, 'null'] format: uri description: The URL of the exported contacts file. Only available when the export is finished. ContactExportRequest: diff --git a/specs/email-sending.openapi.yml b/specs/email-sending.openapi.yml index a22bd01..4276a48 100644 --- a/specs/email-sending.openapi.yml +++ b/specs/email-sending.openapi.yml @@ -4709,15 +4709,12 @@ components: type: string enum: [delivered, not_delivered, enqueued, opted_out] subject: - type: string - nullable: true + type: [string, 'null'] rfc_message_id: - type: string - nullable: true + type: [string, 'null'] description: Value of the RFC 5322 `Message-ID` header. in_reply_to: - type: string - nullable: true + type: [string, 'null'] description: Value of the RFC 5322 `In-Reply-To` header. references: type: array @@ -4725,8 +4722,7 @@ components: type: string description: Values of the RFC 5322 `References` header. thread_id: - type: string - nullable: true + type: [string, 'null'] description: | ID of the inbound thread this message belongs to, or null if the message is not part of one. Use it with the Inbound @@ -4739,23 +4735,20 @@ components: type: string format: date-time client_ip: - type: string - nullable: true + type: [string, 'null'] category: - type: string - nullable: true + type: [string, 'null'] custom_variables: - type: object + type: [object, 'null'] sending_stream: type: string enum: [transactional, bulk] sending_domain_id: type: integer template_id: - type: integer - nullable: true + type: [integer, 'null'] template_variables: - type: object + type: [object, 'null'] opens_count: type: integer clicks_count: @@ -4764,9 +4757,8 @@ components: type: integer description: Total number of messages matching the filters (before pagination). next_page_cursor: - type: string + type: [string, 'null'] format: uuid - nullable: true description: Message UUID to use as search_after for the next page. Null if no more pages. example: messages: @@ -4797,7 +4789,7 @@ components: sending_stream: transactional sending_domain_id: 3938 template_id: null - template_variables: {} + template_variables: null opens_count: 0 clicks_count: 0 total_count: 150 @@ -4813,15 +4805,12 @@ components: type: string enum: [delivered, not_delivered, enqueued, opted_out] subject: - type: string - nullable: true + type: [string, 'null'] rfc_message_id: - type: string - nullable: true + type: [string, 'null'] description: Value of the RFC 5322 `Message-ID` header. in_reply_to: - type: string - nullable: true + type: [string, 'null'] description: Value of the RFC 5322 `In-Reply-To` header. references: type: array @@ -4829,8 +4818,7 @@ components: type: string description: Values of the RFC 5322 `References` header. thread_id: - type: string - nullable: true + type: [string, 'null'] description: | ID of the inbound thread this message belongs to, or null if the message is not part of one. Use it with the Inbound Threads @@ -4843,23 +4831,20 @@ components: type: string format: date-time client_ip: - type: string - nullable: true + type: [string, 'null'] category: - type: string - nullable: true + type: [string, 'null'] custom_variables: - type: object + type: [object, 'null'] sending_stream: type: string enum: [transactional, bulk] sending_domain_id: type: integer template_id: - type: integer - nullable: true + type: [integer, 'null'] template_variables: - type: object + type: [object, 'null'] opens_count: type: integer clicks_count: @@ -5026,14 +5011,11 @@ components: additionalProperties: false properties: sending_ip: - type: string - nullable: true + type: [string, 'null'] recipient_mx: - type: string - nullable: true + type: [string, 'null'] email_service_provider: - type: string - nullable: true + type: [string, 'null'] example: sending_ip: 192.0.2.1 recipient_mx: gmail-smtp-in.l.google.com @@ -5045,8 +5027,7 @@ components: additionalProperties: false properties: web_ip_address: - type: string - nullable: true + type: [string, 'null'] example: web_ip_address: 198.51.100.50 @@ -5056,11 +5037,9 @@ components: additionalProperties: false properties: click_url: - type: string - nullable: true + type: [string, 'null'] web_ip_address: - type: string - nullable: true + type: [string, 'null'] example: click_url: 'https://example.com/track/click/abc123' web_ip_address: 198.51.100.50 @@ -5071,23 +5050,17 @@ components: additionalProperties: false properties: sending_ip: - type: string - nullable: true + type: [string, 'null'] recipient_mx: - type: string - nullable: true + type: [string, 'null'] email_service_provider: - type: string - nullable: true + type: [string, 'null'] email_service_provider_status: - type: string - nullable: true + type: [string, 'null'] email_service_provider_response: - type: string - nullable: true + type: [string, 'null'] bounce_category: - type: string - nullable: true + type: [string, 'null'] example: sending_ip: 192.0.2.1 recipient_mx: mx.example.com @@ -5102,8 +5075,7 @@ components: additionalProperties: false properties: spam_feedback_type: - type: string - nullable: true + type: [string, 'null'] example: spam_feedback_type: abuse @@ -5113,8 +5085,7 @@ components: additionalProperties: false properties: web_ip_address: - type: string - nullable: true + type: [string, 'null'] example: web_ip_address: 198.51.100.50 @@ -5124,8 +5095,7 @@ components: additionalProperties: false properties: reject_reason: - type: string - nullable: true + type: [string, 'null'] example: reject_reason: Policy rejection diff --git a/specs/sandbox.openapi.yml b/specs/sandbox.openapi.yml index 373703f..26b9316 100644 --- a/specs/sandbox.openapi.yml +++ b/specs/sandbox.openapi.yml @@ -2520,7 +2520,7 @@ paths: is_read: false created_at: '2022-07-01T19:29:59.295Z' updated_at: '2022-07-01T19:29:59.295Z' - template_id: 0 + template_id: null template_variables: null html_body_size: 150 text_body_size: 100 @@ -3235,7 +3235,7 @@ paths: is_read: false created_at: '2022-08-19T11:34:33.841Z' updated_at: '2022-08-19T11:34:33.841Z' - template_id: 0 + template_id: null template_variables: null html_body_size: 150 text_body_size: 100 @@ -3679,7 +3679,6 @@ paths: type: array items: type: object - nullable: true properties: Pts: type: number @@ -3857,7 +3856,6 @@ paths: type: array items: type: object - nullable: true properties: error_line: type: number @@ -5209,11 +5207,9 @@ paths: content_type: type: string content_id: - type: string - nullable: true + type: [string, 'null'] transfer_encoding: - type: string - nullable: true + type: [string, 'null'] attachment_size: type: integer created_at: @@ -5395,11 +5391,9 @@ paths: content_type: type: string content_id: - type: string - nullable: true + type: [string, 'null'] transfer_encoding: - type: string - nullable: true + type: [string, 'null'] attachment_size: type: integer created_at: @@ -5562,7 +5556,7 @@ components: type: object description: | Email message captured in a Sandbox. Body URLs are often under `/api/testing_message_parts/...` rather than nested under `/api/accounts/.../messages/...`. - `blacklists_report_info` may contain only `result` or the full report. `template_variables` is set when the message was sent from a template. + `blacklists_report_info` may contain only `result` or the full report. `template_id` and `template_variables` are set when the message was sent from a template. properties: id: type: integer @@ -5589,10 +5583,9 @@ components: updated_at: type: string template_id: - type: integer + type: [integer, 'null'] template_variables: - type: object - nullable: true + type: [object, 'null'] additionalProperties: true html_body_size: type: integer @@ -5668,7 +5661,6 @@ components: sandboxes: type: array items: - nullable: true $ref: '#/components/schemas/TestingSandbox' permissions: type: object @@ -5724,8 +5716,7 @@ components: username: type: string password: - type: string - nullable: true + type: [string, 'null'] description: Password is only available if you have admin permissions for the sandbox. max_size: type: integer @@ -5762,8 +5753,7 @@ components: emails_unread_count: type: integer last_message_sent_at: - nullable: true - type: string + type: [string, 'null'] smtp_ports: type: array items: