Skip to content

Support type: "null" for OpenAPI 3.1 schemas (runtime + TypeNullIn30 rule)#197

Open
takayamaki wants to merge 4 commits into
ota42y:masterfrom
takayamaki:pr8-type-null-in-31
Open

Support type: "null" for OpenAPI 3.1 schemas (runtime + TypeNullIn30 rule)#197
takayamaki wants to merge 4 commits into
ota42y:masterfrom
takayamaki:pr8-type-null-in-31

Conversation

@takayamaki

Copy link
Copy Markdown
Contributor

Continuing the OpenAPI 3.1 work from #195 / #152.

OpenAPI 3.1 (via JSON Schema) adds "null" as a primitive type name.
In 3.0, nullability was expressed via the nullable keyword; type: "null" had no meaning.

This PR adds both runtime validation and version-mismatch detection for type: "null".

Runtime validation

# 3.1 document
schema:
  type: "null"
# nil → valid, "hello" → ValidateError

The accept side and the reject side live in two different validators,
because of how SchemaValidator#validator dispatches:

def validator(value, schema)
  # ...
  return nil_validator if value.nil?   # <- every nil value goes here,
                                       #    before the type dispatch below
  case schema.type
  # ...
  when 'null'
    null_type_validator                # <- only non-nil values can reach this
  # ...
end

Accepting nil

happens in the existing NilValidator, which handles all nil values regardless of schema type. It now treats schema.type == "null" as valid, exactly like the existing nullable: true path.

Rejecting everything else

happens in the new NullTypeValidator. Since nil values are routed to NilValidator before the type dispatch, any value reaching the when 'null' branch is by construction non-nil.
So NullTypeValidator unconditionally returns a validation error.
Without the new branch, type: "null" would fall through to UnspecifiedTypeValidator and accept any value.

SpecValidator rule

TypeNullIn30 walks all schemas and reports a violation when a 3.0 document uses type: "null".
Array-form types like ["string", "null"] are covered by a separate rule in a later PR.

OpenAPIParser.load(
  'spec.yaml',
  strict_specification_version: :warn,
)
# [TypeNullIn30] #/…/schema — `type: "null"` is a 3.1 addition; 3.0 documents have no such primitive

- nil_validator now passes when schema declares `type: \"null\"` even
  without `nullable: true`
- NullTypeValidator handles non-nil values against `type: \"null\"`
  with a ValidateError so 3.1 enforces the singleton-null semantic
- Rules::TypeNullIn30 flags `type: \"null\"` on 3.0 documents
type: "null" on a 3.0 document warns and raises (3.0 has no such
primitive); the same type on a 3.1 document stays clean.
@takayamaki takayamaki marked this pull request as ready for review July 4, 2026 02:45
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.

1 participant