Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nullable ignored if non-null default is present #2144

Open
1 of 2 tasks
luhn opened this issue Feb 7, 2025 · 8 comments · May be fixed by #2145
Open
1 of 2 tasks

Nullable ignored if non-null default is present #2144

luhn opened this issue Feb 7, 2025 · 8 comments · May be fixed by #2145
Labels
bug Something isn't working openapi-ts Relevant to the openapi-typescript library

Comments

@luhn
Copy link

luhn commented Feb 7, 2025

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

  • My OpenAPI schema is valid and passes the Redocly validator (npx @redocly/cli@latest lint)

Extra

@luhn luhn added bug Something isn't working openapi-ts Relevant to the openapi-typescript library labels Feb 7, 2025
@luhn luhn linked a pull request Feb 7, 2025 that will close this issue
3 tasks
@rajmondx
Copy link

rajmondx commented Feb 27, 2025

There is no null type in 3.0:

OpenAPI 3.0 does not have an explicit null type as in JSON Schema, but you can use nullable: true to specify that the value may be null. Note that null is 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/

Image

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.

@luhn
Copy link
Author

luhn commented Feb 27, 2025

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

@rajmondx
Copy link

rajmondx commented Feb 27, 2025

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

  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 follow application/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 valid application/json
  2. Your second link is a more valid argument and explains where the confusion comes from. Yes a value can be null but when defining a type in OAS you can't use null as 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.
  3. I'm truly sorry if the meme hurts your feelings. This was not my intention but my intention was to make you laugh 😂

Image

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.

@luhn
Copy link
Author

luhn commented Feb 27, 2025

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.

@rajmondx
Copy link

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.

@luhn
Copy link
Author

luhn commented Feb 27, 2025

Nice try. I’ll wait for the last word from an actual maintainer 😂

@rajmondx
Copy link

rajmondx commented Feb 27, 2025

😏

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.

@duncanbeevers
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working openapi-ts Relevant to the openapi-typescript library
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants