Skip to content

Replace the OpenAPI 3.0 nullable keyword with 3.1 null types - #66

Open
Rabsztok wants to merge 6 commits into
mainfrom
update-openapi-documentation-schema-to
Open

Rabsztok wants to merge 6 commits into
mainfrom
update-openapi-documentation-schema-to

Conversation

@Rabsztok

@Rabsztok Rabsztok commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Motivation

Every spec declares openapi: 3.1.0, but 47 schemas still marked nulls with the OpenAPI 3.0 nullable: true. OpenAPI 3.1 schemas are JSON Schema 2020-12, which has no nullable and ignores unknown keywords, so those fields rejected null. A response validator fails real responses, such as an API token that never expires (expires_at: null), and SDK generators that read the specs as 3.1 type the fields as non-null. The lint couldn't catch it either, because an unknown keyword is valid in a 3.1 schema.

Changes

  • 50 fields that can be null are now typed [<type>, 'null'], the form contacts and email-sending already use, so they accept null under 3.1
    • Account management: expires_at on API tokens, in responses and in the create and reset request bodies, and on the API token in account accesses, which had no nullable at all
    • Contacts: the string values of contact event params, and the contact export url
    • Email Logs: subject, rfc_message_id, in_reply_to, thread_id, client_ip, category, custom_variables, template_id and template_variables on messages (list and single), next_page_cursor, and the IP, MX, provider, URL and reason fields of the delivery, open, click, bounce, spam, unsubscribe and reject event details
    • Sandbox: attachment content_id and transfer_encoding, message template_id and template_variables, and sandbox password and last_message_sent_at
    • a field's format (date-time, uri, uuid) stays: JSON Schema applies it to strings only, so null still passes
  • three array items drop nullable instead of gaining a null type: the Sandbox spam report Details items, the HTML analysis errors items and a project's sandboxes items. The API never sends them as null, and a nullable item would make generators type the arrays as lists of optional values. The sandboxes one sits next to a $ref, so it never took effect, even under 3.0

  • a Spectral rule, no-nullable-keyword, fails the lint on any nullable in an OpenAPI 3.x spec, so the keyword can't come back. It matches oas3 rather than the 3.1 and 3.2 formats, which Spectral can't load before version 1.9.0 of its formats package, and every spec here is 3.1. It reads the specs unresolved, so a nullable next to a $ref is caught too

How to test

  • The guard: lint main's specs with this branch's .spectral.yaml (npx @stoplight/spectral-cli lint "specs/*.openapi.yml" --ruleset <this branch>/.spectral.yaml). Expect 47 no-nullable-keyword errors: 4 in account management, 3 in contacts, 30 in email sending and 10 in sandbox
  • API tokens: expires_at shows as nullable on the API token responses, on the create and reset request bodies, and on the API token in the account accesses response
  • Email Logs: the message subject, category, custom_variables, template_id and template_variables, and the list's next_page_cursor, show as nullable
  • Sandbox: an attachment's content_id, a message's template_id and a sandbox's last_message_sent_at show as nullable, while the spam report Details and analysis errors items don't

Summary by CodeRabbit

  • Documentation
    • Updated API specifications to represent nullable values with OpenAPI 3.1 type unions. Some fields are no longer marked nullable.
  • Chores
    • Added a specification check that reports uses of the nullable keyword in OpenAPI 3.1 documents and recommends including null in the type.

Rabsztok and others added 2 commits November 9, 2026 09:12
Decisions:
- The documents declare OpenAPI 3.1, whose JSON Schema 2020-12 schemas ignore nullable, so these fields rejected null
- Flow form type: [X, 'null'], the form contacts and email-sending already use
- Three array items lose the keyword instead: they are never null, and a nullable item would make generators type the elements as optional
- The item beside a $ref never took effect, not even under 3.0, which ignores $ref siblings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decisions:
- An unknown keyword is valid in a 3.1 schema, so the built-in rules let nullable through
- The rule reads the unresolved documents, or a nullable beside a $ref vanishes with the resolved ref

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The API specifications replace several nullable: true declarations with OpenAPI 3.1 type unions containing null. The Spectral configuration adds an error-level rule for nullable keywords in OpenAPI 3.1 documents.

Changes: OpenAPI nullability

Layer / File(s) Summary
Update nullable schema declarations
specs/account-management.openapi.yml, specs/contacts.openapi.yml, specs/email-sending.openapi.yml, specs/sandbox.openapi.yml
Multiple fields now use type unions that include null instead of nullable: true. Three sandbox schemas have nullable: true removed without a replacement nullable type.
Add nullable keyword rule
.spectral.yaml
Adds an error-level rule for $..nullable in OpenAPI 3.1 documents. Resolution is disabled, and the message directs users to include null in the type.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: mklocek, oshchyhol, gannarw

Merge Risk: Minimal · up to 69f6c

The nullability updates and lint rule appear mergeable after normal checks.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title states the main change: replacing the OpenAPI 3.0 nullable keyword with OpenAPI 3.1 null types. The raw summary and objectives confirm this. The title is specific and concise, and it match…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description includes Motivation, Changes, and How to test sections with detailed context and test steps. It omits the Images and GIFs section, but this is non-critical for a schema and linting cha…
Full details: Title check

Explanation

The title states the main change: replacing the OpenAPI 3.0 nullable keyword with OpenAPI 3.1 null types. The raw summary and objectives confirm this. The title is specific and concise, and it matches the changeset.

Full details: Description check

Explanation

The description includes Motivation, Changes, and How to test sections with detailed context and test steps. It omits the Images and GIFs section, but this is non-critical for a schema and linting change.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d7a5cfa4-b22f-4a3b-82c4-e368e796bcbd
Commits

Reviewing files that changed from the base of the PR and between c1223a3 and 69f6c50.

Files selected for processing: 5

  • .spectral.yaml
  • specs/account-management.openapi.yml
  • specs/contacts.openapi.yml
  • specs/email-sending.openapi.yml
  • specs/sandbox.openapi.yml

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@Rabsztok

Rabsztok commented Nov 9, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Rabsztok and others added 2 commits November 9, 2026 09:59
Decisions:
- The account accesses endpoints return the token's expires_at as stored, so a token that never expires comes back as null, as the other API token schemas already allow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decisions:
- 3.2 schemas are JSON Schema 2020-12 as in 3.1, so a rule scoped to 3.1 alone would stop firing without notice once the specs move to 3.2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rabsztok
Rabsztok marked this pull request as ready for review November 9, 2026 09:58
Comment thread specs/sandbox.openapi.yml Resolved
Comment thread .spectral.yaml Resolved
Comment thread specs/email-sending.openapi.yml Resolved
Rabsztok and others added 2 commits November 11, 2026 10:50
Decisions:
- A Sandbox message not sent from a template has a null template_id, like its template_variables
- Email Logs render custom_variables and template_variables as null when the stored message has none
- The examples of messages sent without a template show null instead of 0 or an empty object

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decisions:
- Naming oas3.2 makes Spectral releases older than its 1.9.0 formats package refuse the whole ruleset
- oas3 also covers 3.2 and loads on any version; every spec here is 3.1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants