fix: honour OAS required and nullable flags (#3911)#7585
fix: honour OAS required and nullable flags (#3911)#7585OMMHOA wants to merge 7 commits intomicrosoft:mainfrom
Conversation
|
@microsoft-github-policy-service agree |
|
Just saw this issue, and a alarm bell rings ;-): some time ago, I run into a "required" problem with a NSwag generated client: I had to build an api client and the openapi spec was not not correct and did not define fields as optional. After re-generating the client, it failed to parse e.g. server responses because fields missing in the response were considered be required. This might be a sample class (not exactly the property that caused the problem originally): SampleModel:
type: object
properties:
field:
type: numberWith the switch described below, NSwag generates this (working) nullable property: [Newtonsoft.Json.JsonProperty("field", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public double? Field { get; set; }With default settings, it would create a non-nullable property: [Newtonsoft.Json.JsonProperty("field", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public double Field { get; set; }Could this happen here? If yes: could you add a switch to use the old way? NSwag fortunately had a switch for this - https://www.github.com/RicoSuter/NSwag/issues/2313#issuecomment-516471348 |
Implemented with heavy use of AI, manually reviewed the change. AI summary of the change:
Issue #3911 — Implementation Summary
Fixes Kiota generating all model properties as nullable regardless of the OAS
requiredarray andnullableflag.Rule implemented: a property is marked non-nullable only when it is both listed in the parent schema's
requiredarray and its own schema does not carrynullable: true. All other combinations remain nullable (the safe default).Files changed
src/Kiota.Builder/CodeDOM/CodeProperty.cs(previous session)bool IsRequired { get; set; }property.Clone()to copy the field.src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.csinternal static bool IsExplicitlyNullable(this IOpenApiSchema? schema)helper that detects OAS 3.0nullable: trueand OAS 3.1type: null/anyOf [{type: null}]patterns.src/Kiota.Builder/KiotaBuilder.csCreatePropertiesForModelClass— readsschema.Requiredand passesisRequiredto eachCreatePropertycall.CreateProperty— addedbool isRequired = falseparameter; setsprop.IsRequired = isRequiredon every property; setsprop.Type.IsNullable = falsewhen the property is required andIsExplicitlyNullable()returns false. ClonesexistingTypebefore mutation to avoid corrupting shared type references.src/Kiota.Builder/Refiners/CSharpRefiner.csMakeEnumPropertiesNullable— added.Where(x => !x.IsRequired)guard so required enum properties are no longer forced nullable.src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.csisNullableReferenceTypecheck — added&& codeElement.Type.IsNullableso the#nullable enable/?block is only emitted when the type is actually nullable. Required non-nullable properties are written as plainpublic T Name { get; set; }.Tests added
tests/Kiota.Builder.Tests/KiotaBuilderTests.cs7 new tests in
#region Issue-3911verifyingIsNullableandIsRequiredon the Code DOM for:requirednullableIsNullableIsRequiredstringfalsetruestringtruetruestringtruefalsestringtruefalseintegerfalsetrue$reffalsetrue$reffalsetruefalsetruetests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs#nullable enable, no?suffix.#nullable enableand?suffix.#nullable enable, no?suffix.tests/Kiota.Builder.Tests/Writers/Java/CodePropertyWriterTests.cs@jakarta.annotation.Nonnull, no@Nullable.tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs?type prefix, no= nulldefault.tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.csOptional[...], no= Nonedefault.Languages requiring no code changes
Java, PHP, and Python writers already consumed
IsNullablefaithfully and produce correct output as soon as the builder sets the flag correctly. Go, TypeScript, and Ruby were unaffected by design.