Skip to content

Optional properties are not nullable, contrary to OCPI 2.3.0 section 2.8 #39

Description

@wolffseb

Optional properties are not nullable, contrary to OCPI 2.3.0 §2.8

The schemas model optionality only through required. Because they declare openapi: 3.1.0 (JSON Schema 2020-12), an optional property such as type: string accepts a string or absence — but not null.

OCPI 2.3.0 §2.8 (Cardinality) defines optional fields as permitting both encodings:

? — An optional object. If not set, it might be null, or the field might be omitted. When the field is set to null or omitted and it has a default value, the value is the default value.

* — A list of zero or more objects. If empty, it might be null, [] or the field might be omitted.

Since §2.8 defines the cardinality symbols used in every object table in the specification, this governs every optional field in every module. A receiver must accept null, and a sender may legitimately emit it.

The result is that validating a conformant OCPI payload against these schemas produces false errors.

Reproduction

Against ocpi/2.3.0/components/schema.yaml on main, using the 2020-12 dialect that OpenAPI 3.1 mandates:

Payload BusinessDetails Per §2.8 Validator
{"name": "Acme", "website": null} optional string as null valid None is not of type 'string'
{"name": "Acme", "logo": null} optional $ref as null valid None is not of type 'object'
{"before_taxes": 1.0, "taxes": null} optional array as null (Price) valid None is not of type 'array'
{"url": …, "width": null} optional integer as null (Image) valid None is not of type 'integer'

This repository already documents null as permitted

The descriptions affirm what the types reject, which suggests the restriction is unintended rather than a deliberate tightening:

  • ocpi/2.3.0/components/schema.yamlOCPIErrorResponse.data: "Content is not strictly defined by OCPI and may be null."
  • ocpi/2.2.1/modules/locations/sender-interface.yaml — 200 response: "Fields that are not specified may be considered as null values."

The same wording appears in the normative document's module GET descriptions, and §2.1.4 states that on PUT, omitted optional fields "revert to their default value which is either specified in the protocol or NULL."

Scope

334 optional properties across 11 files in ocpi/2.3.0, in three shapes:

Shape Count Suggested encoding
scalar (string/number/integer/boolean) 188 type: [string, "null"]
array 75 type: [array, "null"]
$ref 70 anyOf: [$ref, {type: "null"}]
untyped (OCPIResponse.data) 1 no change — already unconstrained

ocpi/2.2.1 has the same pattern and would need the same treatment.

Questions before doing the bulk change

  1. Is this the intended direction? An alternative reading is that these schemas should describe the recommended encoding (omit rather than null) and stay strict. That would contradict §2.8's "must accept both" requirement for receivers, but it is a defensible editorial choice and worth settling before 334 properties change.
  2. anyOf or oneOf for the $ref case? Both validate correctly here since the referenced schemas never admit null. I've used anyOf as the more conservative option, but will follow your preference.
  3. How would you like it split? One PR per module, one per version, or a single sweep?

I have a reference implementation ready, covering components/schema.yaml only — 9 properties, all three shapes — so the pattern can be reviewed before it is applied broadly:

main...wolffseb:fix/nullable-optional-properties — 1 file, 11 lines.

It applies the encodings in the table above. Validating payloads against that file with the 2020-12 dialect gives 12/12 passing afterwards versus 8/12 before, where four of the checks are guard rails confirming that required fields, wrong types and malformed $ref values are all still rejected. npm run build:ocpi:2.3.0 completes successfully.

I wasn't able to open it as a pull request — CreatePullRequest returns a permissions error for my account, and I notice the repository has no PRs to date, so I assume they aren't open to outside contributors yet. Happy to submit it in whatever form suits you, and to do the remaining modules once the approach is agreed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions