Skip to content

feat(library): Preserve PatternProperties via x-jsonschema-patternProperties extension for OpenAPI v2/v3.0#2755

Merged
baywet merged 2 commits intomainfrom
copilot/preserve-patternproperties-serialization
Mar 4, 2026
Merged

feat(library): Preserve PatternProperties via x-jsonschema-patternProperties extension for OpenAPI v2/v3.0#2755
baywet merged 2 commits intomainfrom
copilot/preserve-patternproperties-serialization

Conversation

Copy link
Contributor

Copilot AI commented Mar 4, 2026

OpenApiSchema.PatternProperties was silently dropped during serialization to OpenAPI v2.0 and v3.0. This PR preserves the semantic intent via the x-jsonschema-patternProperties vendor extension (consistent with the existing x-jsonschema-unevaluatedProperties pattern), and restores the property during deserialization when the extension is present.

Description

patternProperties is not part of the OpenAPI v2.0 or v3.0 schema dialect, but the library's object model supports it. Previously, any schema with PatternProperties set would silently lose that data when serialized to those versions. This change round-trips the value via a vendor extension for v2/v3.0, leaving v3.1/v3.2 behavior unchanged.

Serialization (v2.0 and v3.0 only):

{
  "type": "object",
  "x-jsonschema-patternProperties": {
    "^[a-z][a-z0-9_]*$": { "type": "integer", "format": "int32" }
  }
}

Deserialization: reading x-jsonschema-patternProperties in a v2/v3.0 document populates PatternProperties directly (not stored as a raw extension).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Changes Made

  • OpenApiConstants: Added PatternPropertiesExtension = "x-jsonschema-patternProperties"
  • OpenApiSchema.SerializeInternal: Emits the extension when PatternProperties is non-empty and version < 3.1
  • OpenApiSchema.SerializeAsV2: Same, for v2.0 serialization path
  • Reader/V2/OpenApiSchemaDeserializer: Added x-jsonschema-patternProperties as a fixed field that directly populates PatternProperties (takes precedence over the generic x- extension handler)
  • Reader/V3/OpenApiSchemaDeserializer: Same for v3.0
  • PublicAPI.Unshipped.txt: Registered new public constant

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • All existing tests pass

Tests added:

  • SerializePatternPropertiesAsKeywordInV31AndV32 — no behavior change in v3.1+
  • SerializePatternPropertiesAsExtensionInEarlierVersions — extension emitted for v2.0/v3.0
  • SerializeEmptyPatternPropertiesNotEmittedInEarlierVersions — no extension emitted for empty map
  • DeserializePatternPropertiesExtensionInV2AssignsPatternPropertiesProperty — round-trip v2.0
  • DeserializePatternPropertiesExtensionInV3AssignsPatternPropertiesProperty — round-trip v3.0

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Versions applicability

  • My change applies to the version 1.X of the library, if so PR link:
  • My change applies to the version 2.X of the library, if so PR link:
  • My change applies to the version 3.X of the library, if so PR link:
  • I have evaluated the applicability of my change against the other versions above.

Additional Notes

Follows the same pattern established by x-jsonschema-unevaluatedProperties. The extension name x-jsonschema-patternProperties explicitly signals JSON Schema keyword preservation and avoids collision with other tooling extensions.

Original prompt

This section details on the original issue you should resolve

<issue_title>OpenAPI 3.0: Preserve PatternProperties via Vendor Extension during Serialization</issue_title>
<issue_description>## Summary

When generating OpenAPI 3.0 documents using OpenAPI.NET, schemas that define
PatternProperties lose their semantic meaning during serialization.

Currently, the serializer either:

  • drops the information entirely, or
  • emits additionalProperties: false, which is semantically incorrect for
    dictionary-like schemas with patterned keys.

This issue proposes preserving PatternProperties in a spec-compliant way
for OpenAPI 3.0 by emitting a vendor extension, while keeping a reasonable
fallback for standard tooling.


Background

patternProperties is a core JSON Schema feature that has existed since early
drafts and is fully supported in:

  • JSON Schema (all modern drafts)
  • OpenAPI 3.1+ (which aligns with JSON Schema 2020-12)

However, OpenAPI 3.0 uses a restricted schema dialect and does not
support patternProperties.

OpenAPI.NET already exposes:

OpenApiSchema.PatternProperties

but this information is effectively lost when serializing to OpenAPI 3.0.


Current Behavior

Given a schema intent like:

{
  "type": "object",
  "patternProperties": {
    "^[a-z][a-z0-9_]*$": {
      "type": "integer",
      "format": "int32"
    }
  }
}

OpenAPI 3.0 serialization may produce:

{
  "type": "object",
  "additionalProperties": false
}

This output is:

  • syntactically valid OpenAPI 3.0
  • semantically incorrect, because it forbids all dynamic keys

Expected / Proposed Behavior

When serializing OpenAPI 3.0 and OpenApiSchema.PatternProperties is present:

1. Preserve semantic intent using a vendor extension

Emit a vendor extension such as:

"x-jsonSchema-patternProperties": {
  "^[a-z][a-z0-9_]*$": {
    "type": "integer",
    "format": "int32"
  }
}

Vendor extensions are explicitly allowed in OpenAPI 3.0 and are the only
spec-compliant mechanism to preserve this information.

2. Provide a best-effort OpenAPI 3.0 fallback

Additionally emit one of the following (depending on feasibility):

  • If all pattern properties share the same schema:

    "additionalProperties": {
      "type": "integer",
      "format": "int32"
    }
  • Otherwise:

    "additionalProperties": true

This ensures existing OpenAPI 3.0 tooling continues to function predictably,
while advanced consumers can still read the extension.


Non-Goals

  • This proposal does not attempt to make patternProperties a first-class
    OpenAPI 3.0 keyword (that would be non-spec).
  • This proposal does not change OpenAPI 3.1+ behavior.

Scope of Change

  • Affects serialization only
  • Only for OpenApiSpecVersion.OpenApi3_0
  • No changes to the public object model
  • No breaking changes

Benefits

  • Prevents silent loss of schema semantics
  • Produces valid OpenAPI 3.0 output
  • Allows downstream tools to recover JSON Schema intent
  • Aligns with OpenAPI’s intended use of vendor extensions

Suggested Extension Name

x-jsonSchema-patternProperties

Rationale:

  • Explicitly indicates JSON Schema keyword preservation
  • Avoids ambiguity with standard OpenAPI fields
  • Minimizes risk of collision with other extensions

References


Closing Notes

This change would allow OpenAPI.NET to preserve important schema semantics
without violating the OpenAPI 3.0 specification, and without requiring users
to fork or post-process the library output.

Thank you for considering this enhancement.
</issue_description>

<agent_instructions>implement a fix for this issue.
start by defining unit tests first.
we want the pattern properties property to be serialized as an extension (x-jsonSchema-...) when it's assigned and when we're serializing to v2 or v3. For 3.1 or 3.2 it should remain serialized as it is.
During deserialization, if that extension is present, we should read it and assign the property for those two versions specifically.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@baywet Hi @mdaneri Thank you for using the SDK and for reaching out.

This is something we have precedent for, look for x-oai in the repository. The only "question" I have is the extension name: should we align on x-oai for consistency so users know they are "compatibility" properties at glance, or should we introduce the jsonschema suggestion you've made, so users know where this is sourced from? I do...


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…erties extension for OpenAPI v2/v3.0 serialization

- Add PatternPropertiesExtension constant ("x-jsonschema-patternProperties")
- Emit extension when serializing to OpenAPI v2.0 or v3.0 and PatternProperties is non-empty
- Parse the extension back into PatternProperties when deserializing v2.0 or v3.0 documents
- Add unit tests for both serialization and deserialization round-trip

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Copilot AI changed the title [WIP] Preserve PatternProperties in OpenAPI 3.0 serialization feat(library): Preserve PatternProperties via x-jsonschema-patternProperties extension for OpenAPI v2/v3.0 Mar 4, 2026
@baywet baywet marked this pull request as ready for review March 4, 2026 14:37
@baywet baywet requested a review from a team as a code owner March 4, 2026 14:37
@baywet baywet enabled auto-merge March 4, 2026 14:37
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 4, 2026

@baywet baywet merged commit 16ab5e4 into main Mar 4, 2026
18 checks passed
@baywet baywet deleted the copilot/preserve-patternproperties-serialization branch March 4, 2026 15:48
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.

OpenAPI 3.0: Preserve PatternProperties via Vendor Extension during Serialization

3 participants