Nullable ignored if non-null default is present
openapi-typescript version
7.6.1
Node.js version
23.7.0
OS + version
macOS 15.3
Description
Take the example property defined as "nullable" using OpenAPI 3.1 syntax.
"foo": {
"type": ["string", "null"]
}
Results in:
foo?: string | null
However, if you add a non-null default:
"foo": {
"type": ["string", "null"],
"default": "bar"
}
It eliminates the null type:
foo?: string
This is problematic because my API has properties that have non-null defaults, but null is still a valid value to return.
I also tried with --default-non-nullable false but the behavior is the same.
This is very possibly the same issue as #2055, but using the 3.1 syntax.
Reproduction
{
"openapi": "3.1.1",
"info": {
"title": "Test",
"version": "local",
"license": {
"name": "Unlicensed",
"identifier": "UNLICENSED"
}
},
"servers": [
{"url": "https://openapi-ts.dev"}
],
"security": [],
"paths": {
"/test": {
"post": {
"summary": "Test",
"operationId": "test",
"parameters": [],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestSchema"
}
}
}
},
"404": {
"description": "Not found!"
}
}
},
}
},
"components": {
"schemas": {
"TestSchema": {
"properties": {
"nullable": {
"type": ["string", "null"]
},
"nullable_default": {
"type": ["string", "null"],
"default": "foo"
}
},
"type": "object",
"required": [],
"title": "TestSchema"
}
}
}
}
Gives (in part):
TestSchema: {
nullable?: string | null;
/** @default foo */
nullable_default?: string;
};
Expected result
TestSchema: {
nullable?: string | null;
/** @default foo */
nullable_default?: string | null;
};
Required
- [x] My OpenAPI schema is valid and passes the Redocly validator (
npx @redocly/cli@latest lint)
Extra
- [ ] I’m willing to open a PR (see CONTRIBUTING.md)
There is no null type in 3.0:
OpenAPI 3.0 does not have an explicit
nulltype as in JSON Schema, but you can usenullable: trueto specify that the value may benull. Note thatnullis different from an empty string "".
# Correct
type: integer
nullable: true
# Incorrect
type: null
# Incorrect as well
type:
- integer
- null
See https://swagger.io/docs/specification/v3_0/data-models/data-types/
Edit: The idea behind this is to avoid having union lists and being able to differentiate them e.g. a (null | string)[] is not the same as a nullable string[]. Hope this helps to understand why there is no null type 👍
Edit 2: To avoid confusion: There is no 'boolean' type neither. See https://www.json.org/json-en.html for further information. The values false, true (and also null) are considered literals and not types in JSON, see more in https://www.crockford.com/mckeeman.html, so technically speaking, there isn't even a 'boolean' type, but just literals that can be false, true and null in values.
Maybe before posting snarky memes, you should read the documentation. As I specify in my issue, I'm using 3.1 which does have a null type. I also ran my spec through Redocly, which gave no validation issues.
Data types in the OAS are based on the types defined by the JSON Schema Validation Specification Draft 2020-12: "null", "boolean", "object", "array", "number", "string", or "integer".
https://swagger.io/specification/
The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and MUST be unique.
String values MUST be one of the six primitive types ("null", "boolean", "object", "array", "number", or "string"), or "integer" which matches any number with a zero fractional part.
https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#section-6.1.1
Maybe before posting snarky memes, you should read the documentation. As I specify in my issue, I'm using 3.1 which does have a null type. I also ran my spec through Redocly, which gave no validation issues.
Data types in the OAS are based on the types defined by the JSON Schema Validation Specification Draft 2020-12: "null", "boolean", "object", "array", "number", "string", or "integer".
https://swagger.io/specification/
The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and MUST be unique. String values MUST be one of the six primitive types ("null", "boolean", "object", "array", "number", or "string"), or "integer" which matches any number with a zero fractional part.
https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-00#section-6.1.1
- Regarding your first link: You are confusing the schema reference for
application/schema+json(content type) with OpenAPI schema. OpenAPI schemas don't have to followapplication/schema+json(which was rejected afaik, at least the draft status is expired). Imagine it like saying Why is{"foo": "boo"}not a valid OpenAPI schema, it is a validapplication/json - Your second link is a more valid argument and explains where the confusion comes from. Yes a value can be
nullbut when defining atypein OAS you can't usenullas type (type definition != value type), see Note that there is no null type; instead, the nullable attribute is used as a modifier of the base type. - I'm truly sorry if the meme hurts your feelings. This was not my intention but my intention was to make you laugh 😂
Edit: Long explaination
Edit: Imagine application/schema+json as schema validation for any kind of json. You can say how your JSON should look like e.g. You can define a schema validator for tsconfig.json or the body of a DTO. It's similar to what XLS is to XML. Afaik OpenAPI itself is using application/schema+json to validate OpenAPI schemas and the idea (probably) was to use application/schema+json also as OpenAPI schema itself but was rejected due to:
The relationship between OpenAPI and JSON Schema can be a source of some confusion. Here's a breakdown of why OpenAPI has its own schema definition, and how it relates to JSON Schema:
Key Differences and Purposes:
-
OpenAPI:
- OpenAPI is a specification for describing RESTful APIs. It defines the structure of APIs, including endpoints, operations, request and response formats, authentication, and more.
- Its primary purpose is to enable both humans and machines to understand and interact with APIs.
- While it leverages JSON Schema for defining data structures, OpenAPI itself describes the API's overall structure, not just the data.
-
JSON Schema:
- JSON Schema is a specification for describing the structure of JSON data.
- It's used for validating that JSON data conforms to a specific format.
- In the context of OpenAPI, JSON Schema is used to define the structure of request and response bodies.
Why OpenAPI Has Its Own Definition:
-
API Description vs. Data Description:
- OpenAPI's scope is much broader than JSON Schema's. It needs to describe the entire API, including things like HTTP methods, paths, and security schemes, which are outside the scope of JSON Schema.
- Therefore, it requires its own specification to define these API-specific elements.
-
Evolution and Compatibility:
- While OpenAPI has increasingly aligned with JSON Schema, especially in newer versions (like OpenAPI 3.1), there have historically been differences in the supported keywords and features.
- OpenAPI has needed to maintain its own definition to ensure compatibility and consistency within the API description ecosystem.
-
Control and Extensibility:
- Having its own definition allows the OpenAPI initiative to control the evolution of the specification and add features specific to API description.
But there is hope: OpenAPI and JSON Schema Integration:
- OpenAPI uses JSON Schema to define the structure of data models within API requests and responses.
- OpenAPI 3.1 significantly improves compatibility with JSON Schema, allowing for greater use of standard JSON Schema features.
TLDR
In essence, OpenAPI is a higher-level specification that uses JSON Schema as a component for data modeling. They serve different but complementary purposes.
Once again, you’re referencing 3.0. 3.1 introduces “null” as a valid type. If you want proof just run my spec through Redocly.
Nice ChatGPT edit there.
Once again, you’re referencing 3.0. 3.1 introduces “null” as a valid type. If you want proof just run my spec through Redocly.
Where do you get this? The doc (which I wrote btw) is clearly saying that Note that there is no null type; instead, the nullable attribute is used as a modifier of the base type.
Nice ChatGPT edit there.
Thank you 😂 It's Google Gemini Advanced.
My last words in this matter
I hope everything is clear now. If you have any further questions, feel free to ask. I'm gonna allow you the dignity to reject your own PR, otherwise I'm gonna reject it anyway in 2 weeks.
Nice try. I’ll wait for the last word from an actual maintainer 😂
😏
But now for real: Yes I'm not the maintainer nor did I contribute a single char into the code. And afaik the maintainer of the repo here (openapi-typescript) are not affiliated to the maintainers of Swagger nor OpenAPI Schema?
My strongest argument: But I guess you understand that a null type would allow to have union types in lists?
e.g. (null | string)[] instead of nullable string[]
How are you going to differ between them?
Imo (I'm just engaging in a fantasy rn) OpenAPI should replace OpenAPI Schema not with JSON Schema, but use directly TypeScript itself as schema for an API, that would OP because what JSON Schema and OpenAPI Schema are doing (imo) is just replicating the features that TypeScript already offers.
The description of how nulls are handled different between OpenAPI 3.0 and 3.1 is accurate.
This does indeed appear to be a bug. 🐞
Handling default has been a bit tricky, and I'll be sure to include this discussion as we're looking at handling its presence accurately for both schema versions.
Imo (I'm just engaging in a fantasy rn) OpenAPI should replace OpenAPI Schema not with JSON Schema
@rajmondx You may be interested in TypeSpec.