Skip to content

Upgrading to v2

David Kallesen edited this page Sep 11, 2026 · 1 revision

⬆️ Upgrading to v2

Who needs to read this: anyone generating from an OpenAPI 3.0 document that uses nullable: true on a property that has no type of its own β€” typically alongside allOf or oneOf.

If your specifications do not contain that shape, v2 is a drop-in upgrade and you can stop here. The generator will tell you: build with "validateSpecificationStrategy": "Strict" and rule ATC_API_VER001 reports every occurrence with a line number.


πŸ”„ What changed

v2 moves to Microsoft.OpenApi 3.10.2, which brought the parser in line with the OpenAPI specification on one point: nullable: true only applies when type is declared in the same Schema Object, and it does not reach through allOf / oneOf.

Earlier parser versions honoured it anyway. Generated code therefore treated some properties as nullable that the specification never considered nullable.

The affected shape

billingAccount:
  nullable: true          # no `type` beside it
  oneOf:
    - $ref: '#/components/schemas/IdName'

What your generated code does now

- public IdName? BillingAccount { get; init; }
+ public IdName BillingAccount { get; init; }
- readonly billingAccount?: IdName | null;
+ readonly billingAccount?: IdName;

⚠️ This does not break your build β€” that is what makes it worth your attention. The property is still optional, so everything compiles. Under <Nullable>enable</Nullable> or strictNullChecks the value is simply no longer declared as possibly-null, so the compiler stops warning about unguarded access at exactly the places a null can still arrive over the wire.


❓ Am I affected?

Search your specifications for nullable: true and check whether each one has a type: at the same indentation, in the same mapping block. The generator does this for you β€” see ATC_API_VER001 in Analyzer Rules.

Shape Affected?
type: string + nullable: true βœ… No β€” valid OpenAPI 3.0, still works
type: [string, "null"] βœ… No β€” the OpenAPI 3.1 form, works
nullable: true with allOf / oneOf and no type ❌ Yes
nullable: true with no type at all ❌ Yes

πŸ”§ How to fix it

First decide, per property, whether it should be nullable at all. This shape has been a no-op for as long as the specification has existed, so the API may genuinely never return null β€” in which case the right fix is to delete the nullable: true, not translate it. Translating on autopilot widens contracts that were already correct.

Where the property is genuinely nullable:

Staying on OpenAPI 3.0 β€” nest the composition inside a oneOf with a nullable branch:

billingAccount:
  oneOf:
    - $ref: '#/components/schemas/IdName'
    - type: object
      nullable: true

On OpenAPI 3.1 or later β€” use the null type, which is cleaner and needs no restructuring:

billingAccount:
  oneOf:
    - $ref: '#/components/schemas/IdName'
    - type: "null"

Then regenerate and diff. Once fixed, the diff against your v1 output should be empty.


βœ… What did not change

Backwards compatibility was kept everywhere the information survives parsing:

Spelling 3.0 3.1 3.2
type: string + nullable: true βœ… βœ… βœ…
type: [string, "null"] n/a βœ… βœ…
nullable: true + allOf: [$ref] ❌ βœ… βœ…
oneOf: [$ref, {type: "null"}] n/a βœ… βœ…
oneOf: [$ref, {type: object, nullable: true}] βœ… βœ… βœ…

nullable: true is still honoured in OpenAPI 3.1 and 3.2 documents even though the keyword was removed from the specification there β€” a deliberate compatibility choice, so that moving a specification to 3.1 does not silently change your models.

The single ❌ is the case in this guide: in a 3.0 document the parser consumes the keyword and discards it, leaving nothing for the generator to act on.


✨ Also new in v2

  • Four migration rules, ATC_API_VER001–VER004, report the constructs whose meaning depends on the declared OpenAPI version β€” each with a line number, a suggested rewrite and a link back here. See Working with Nullability.
  • Nullable references in a oneOf are now understood β€” both {type: "null"} (3.1) and {type: object, nullable: true} (3.0). Previously either extra branch degraded the property to object / unknown. This is what makes the fix above actually produce IdName?.
  • Multi-reference oneOf / anyOf properties emit a TypeScript union (A | B | C) instead of unknown, matching what the Zod schema emitter already produced.
  • HTTP QUERY (OpenAPI 3.2) is supported across all three client flavours β€” see Working with OpenAPI.

πŸ“š Background

Working with Nullability has the full story: what the OpenAPI Initiative changed and why, the specification wording this rests on, a version-by-version comparison of parser behaviour, and links to the primary sources.

🏠 Home

πŸ’Ό Why This Tool?

πŸ“– Getting Started

βš™οΈ Features

🌐 Frontend

πŸ“‹ Reference


πŸ”— Resources

Clone this wiki locally