I'm using NSagStudio to generate a c# client for an OpenAPI 3.0.1 service. Since the latest update I get an issue where a property marked as required is missing from the retrieved data and thus cannot be deserialized.
I'm trying to understand if
- The OpenAPI spec of the service is incomplete/wrong
- I've misconfigured something with NSwagStudio
- There is a bug in NSwagStudio
OpenAPI 3.0.1 service spec: https://raw.githubusercontent.com/admin-ch/CovidCertificate-Apidoc/main/open-api/api-doc.yaml
NSwagStudio configuration:
{
"runtime": "NetCore31",
"defaultVariables": null,
"documentGenerator": {
"fromDocument": {
"json": "[see URL]",
"url": "https://raw.githubusercontent.com/admin-ch/CovidCertificate-Apidoc/main/open-api/api-doc.yaml",
"output": null,
"newLineBehavior": "Auto"
}
},
"codeGenerators": {
"openApiToCSharpClient": {
"clientBaseClass": "BagCovidCertificateClientInternalBase",
"configurationClass": null,
"generateClientClasses": true,
"generateClientInterfaces": false,
"clientBaseInterface": null,
"injectHttpClient": false,
"disposeHttpClient": true,
"protectedMethods": [],
"generateExceptionClasses": true,
"exceptionClass": "BagCovidCertificateApiException",
"wrapDtoExceptions": true,
"useHttpClientCreationMethod": false,
"httpClientType": "System.Net.Http.HttpClient",
"useHttpRequestMessageCreationMethod": true,
"useBaseUrl": true,
"generateBaseUrlProperty": true,
"generateSyncMethods": false,
"generatePrepareRequestAndProcessResponseAsAsyncMethods": false,
"exposeJsonSerializerSettings": false,
"clientClassAccessModifier": "internal",
"typeAccessModifier": "internal",
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
"parameterDateTimeFormat": "s",
"parameterDateFormat": "yyyy-MM-dd",
"generateUpdateJsonSerializerSettingsMethod": true,
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"className": "BagCovidCertificateClientInternal",
"operationGenerationMode": "SingleClientFromOperationId",
"additionalNamespaceUsages": [],
"additionalContractNamespaceUsages": [],
"generateOptionalParameters": false,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"parameterArrayType": "System.Collections.Generic.IEnumerable",
"parameterDictionaryType": "System.Collections.Generic.IDictionary",
"responseArrayType": "System.Collections.Generic.ICollection",
"responseDictionaryType": "System.Collections.Generic.IDictionary",
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"namespace": "Documedis.Clients.External.Clients.Internal",
"requiredPropertiesMustBeDefined": true,
"dateType": "System.DateTimeOffset",
"jsonConverters": null,
"anyType": "object",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"classStyle": "Poco",
"jsonLibrary": "NewtonsoftJson",
"generateDefaultValues": true,
"generateDataAnnotations": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"jsonSerializerSettingsTransformationMethod": null,
"inlineNamedArrays": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedAny": false,
"generateDtoTypes": true,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": null,
"serviceSchemes": null,
"output": "BagCovidCertificateClientInternal.Generated.cs",
"newLineBehavior": "Auto"
}
}
}
My issue occurs with this element:
IssuableRapidTestDto:
type: object
properties:
code:
type: string
description: Code of rapid test as string.
example: "1232"
display:
type: string
description: Manufacturer and display name of rapid test as string.
example: "Abbott Rapid Diagnostics, Panbio Covid-19 Ag Rapid Test"
validUntil:
type: string
description: Deadline after which the rapid-test can no longer be used to
establish a certificate.
format: date-time
example: 2022-01-06T00:00:00+01:00
Which results in following class being generated:
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.15.5.0 (NJsonSchema v10.6.6.0 (Newtonsoft.Json v12.0.0.0))")]
internal partial class IssuableRapidTestDto
{
[...]
/// <summary>
/// Deadline after which the rapid-test can no longer be used to establish a certificate.
/// </summary>
[Newtonsoft.Json.JsonProperty("validUntil", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.DateTimeOffset ValidUntil { get; set; }
[...]
}
My issue occurs because not all IssuableRapidTestDto
have a ValidUntil
date set, when retrieving the data.
If I remove Required = Newtonsoft.Json.Required.DisallowNull
the deserialization works and ValidUntil
holds DateTimeOffet.MinValue
. As this is generated code I don't want to adapt it manually.
I'm having a hard time figuring out if ValidUntil
is actually required or not.