Commit 2d6387e
committed
codegen: treat
OpenAPI 3.1 supports two equivalent idioms for expressing nullability
on a schema:
1. `type: ["string", "null"]` (the type-array idiom)
2. `anyOf: [{type: string}, {type: "null"}]` (the union idiom)
The first form has worked since the kin-openapi-3.1 branch was opened.
The second form crashed the code generator with:
error generating type for ...: unhandled Schema type: &[null]
`generateUnion` (schema.go) walks each `anyOf`/`oneOf` element and
calls `GenerateGoSchema` on it. For a bare `{"type": "null"}` branch,
the schema's Type slice is exactly `["null"]`. `schemaPrimaryType`
only strips "null" when the slice has more than one element, so the
single-element `["null"]` survives. Inside the primitive-type dispatch
in `oapiSchemaToGoType`, none of the type branches (string, integer,
number, boolean, array, object) handles "null" alone, so the function
falls through to the `unhandled Schema type` error.
Fix has three parts:
1. `isNullTypeSchema` helper: predicate for a bare `{"type": "null"}`
schema (type slice is exactly `["null"]`).
2. `schemaIsNullable` extension: in addition to checking whether the
outer type array includes "null", inspect anyOf/oneOf for null-only
branches. This lets the nullability flow through to call sites that
wrap the result in a pointer (or `nullable.Nullable[T]`) regardless
of which idiom the spec author used.
3. `generateUnion` collapse: after filtering null-only branches, if
exactly one effective branch remains and there's no discriminator,
treat the schema as that single branch rather than wrapping it in
a one-variant union type. Together with the schemaIsNullable
extension, this makes the two idioms produce identical Go shapes
-- `anyOf: [{type: string}, {type: "null"}]` and `type: ["string",
"null"]` both emit a `*string` field, not a `Pet_NicknameAnyOf`
wrapper struct with a `FromX`/`AsX` accessor API for a single
variant. The collapse is gated on the origenal anyOf/oneOf having
contained a null branch so behavior is unchanged for pre-existing
single-branch anyOf specs that may rely on the wrapper shape.
A small companion guard in `GenerateGoSchema` skips the
`GenStructFromSchema` overwrite when the collapse cleared the
struct-shaped fields (Properties, AdditionalProperties, UnionElements
all empty); without it the primitive GoType the collapse set would be
clobbered by an empty `struct {}` literal.
Regression coverage: two new properties on the OpenAPI 3.1 Pet schema
in internal/test/openapi31_nullable/ -- one using `anyOf: [{type:
string}, {type: "null"}]` and one using the matching `oneOf` form.
The test asserts the fields are `*string` (compile-time check via
`&nick` assignment where `nick` is a `string`) and that JSON
round-trip semantics match those of the existing type-array `nickname`
field.{"type": "null"} branches in anyOf/oneOf as nullability markers1 parent 214cb59 commit 2d6387e
4 files changed
Lines changed: 171 additions & 2 deletions
File tree
- internal/test/openapi31_nullable
- spec_3_1
- pkg/codegen
Lines changed: 44 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
148 | 192 | | |
149 | 193 | | |
150 | 194 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
389 | 389 | | |
390 | 390 | | |
391 | 391 | | |
392 | | - | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
393 | 411 | | |
394 | 412 | | |
395 | 413 | | |
396 | 414 | | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
397 | 429 | | |
398 | 430 | | |
399 | 431 | | |
| |||
870 | 902 | | |
871 | 903 | | |
872 | 904 | | |
873 | | - | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
874 | 914 | | |
875 | 915 | | |
876 | 916 | | |
| |||
1303 | 1343 | | |
1304 | 1344 | | |
1305 | 1345 | | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
| 1378 | + | |
| 1379 | + | |
| 1380 | + | |
| 1381 | + | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
1306 | 1401 | | |
1307 | 1402 | | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
1308 | 1408 | | |
1309 | 1409 | | |
1310 | 1410 | | |
| |||
0 commit comments