openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[BUG] cshar .net6 DateOnly not nullable

Open Noudicus opened this issue 11 months ago • 2 comments

Bug Report Checklist

  • [x] Have you provided a full/minimal spec to reproduce the issue?
  • [ ] Have you validated the input using an OpenAPI validator (example)?
  • [ ] Have you tested with the latest master to confirm the issue still exists?
  • [x] Have you searched for related issues/PRs?
  • [x] What's the actual output vs expected output?
  • [ ] [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

When generating a client for csharp .net6 the nullable parameter is not applied to the DateOnly property

openapi-generator version

v7.3.0

OpenAPI declaration file content or url
{
    "openapi": "3.0.1",
    "info": {
        "title": "Test API",
        "description": "Test",
        "contact": {
            "name": "Test",
            "email": "[email protected]"
        },
        "version": "1.0"
    },
    "servers": [
        {
            "url": "https://api.test.net"
        }
    ],
    "security": [
        {
            "oAuth2": []
        }
    ],
    "tags": [        
        {
            "name": "Reservation",
            "description": "test"
        }
    ],
    "paths": {
        "/v1/Reservation": {
            "get": {
                "tags": [
                    "Reservation"
                ],
                "summary": "Test",
                "description": "Test",
                "operationId": "getReservation",
                "responses": {
                    "200": {
                        "description": "The request is completed successfully without any errors",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Reservation"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "No resorts found for given criteria."
                    },
                    "500": {
                        "description": "Error occurred while fetching Reservation."
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {            
            "Reservation": {
                "type": "object",
                "properties": {
                    "tncSignedDate": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    }
                }
            }
        }
    }
}
Generation Details

Config:

{
    "packageName": "Test.PublicApi",
    "packageVersion": "2024.3.1.1",
    "targetFramework": "net6.0"
}

java -jar ../Generator/openapi-generator-cli-7.3.0.jar generate -g csharp -i openapi.json -o output --config config/GeneratorConfig.json

Steps to reproduce

Generate above

Related issues/PRs
Suggest a fix

Noudicus avatar Mar 01 '24 17:03 Noudicus

Can confirm. It generates code like this, even though it is marked as nullable: true:

    [DataContract(Name = "cargoReadyDate")]
    public partial class CargoReadyDate : IEquatable<CargoReadyDate>, IValidatableObject
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CargoReadyDate" /> class.
        /// </summary>
        /// <param name="currentValue">currentValue.</param>
        /// <param name="previousValue">previousValue.</param>
        public CargoReadyDate(DateOnly currentValue = default(DateOnly), DateOnly previousValue = default(DateOnly))
        {
            this.CurrentValue = currentValue;
            this.PreviousValue = previousValue;
        }

        /// <summary>
        /// Gets or Sets CurrentValue
        /// </summary>
        [DataMember(Name = "currentValue", EmitDefaultValue = true)]
        [JsonConverter(typeof(OpenAPIDateConverter))]
        public DateOnly CurrentValue { get; set; }

        /// <summary>
        /// Gets or Sets PreviousValue
        /// </summary>
        [DataMember(Name = "previousValue", EmitDefaultValue = true)]
        [JsonConverter(typeof(OpenAPIDateConverter))]
        public DateOnly PreviousValue { get; set; }
    /// <summary>
    /// Formatter for 'date' openapi formats ss defined by full-date - RFC3339
    /// see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#data-types
    /// </summary>
    public class OpenAPIDateConverter : IsoDateTimeConverter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="OpenAPIDateConverter" /> class.
        /// </summary>
        public OpenAPIDateConverter()
        {
            // full-date   = date-fullyear "-" date-month "-" date-mday
            DateTimeFormat = "yyyy-MM-dd";
        }
    }

0x326 avatar Apr 25 '24 14:04 0x326

Made a TestProject to collect errors regarding DateOnly, which includes this error: https://github.com/MichaelMay81/OpenApiGeneratorTest

MichaelMay81 avatar Apr 30 '24 12:04 MichaelMay81

I recognized that DateOnly will only be handled as a nullable value type when using the library GENERICHOST. When using the library HTTPCLIENT I experience the same problem as described in this issue. Adding DateOnly to the getNullableTypes and getValueTypes method in CSharpClientCodegen fixes the error for me.

What is the reason why some types are not present in the overrrides of getNullableTypes (e.g. Dateonly) and getValueTypes (e.g. DateTime, DateOnly, DateTimeOffset, Guid) when the library isn't GENERICHOST?

jpduchon avatar May 27 '24 14:05 jpduchon

I've also noticed this for strings (as in I make a string nullable but the generated client code does not mark it as "string?"), I assume there is a reason for that but does anybody know why?

alec-petersen avatar Aug 05 '24 12:08 alec-petersen

I recognized that DateOnly will only be handled as a nullable value type when using the library GENERICHOST. When using the library HTTPCLIENT I experience the same problem as described in this issue. Adding DateOnly to the getNullableTypes and getValueTypes method in CSharpClientCodegen fixes the error for me.

What is the reason why some types are not present in the overrrides of getNullableTypes (e.g. Dateonly) and getValueTypes (e.g. DateTime, DateOnly, DateTimeOffset, Guid) when the library isn't GENERICHOST?

There are only reference types or value types. Nullable types was a misnomer and there were some other issues of which I don't really recall now. Generichost does not use getNullableTypes at all, the abstract C# codegen throws an exception if it is used. Other C# implementations were excluded from the change to narrow the scope of my pr.

I've also noticed this for strings (as in I make a string nullable but the generated client code does not mark it as "string?"), I assume there is a reason for that but does anybody know why?

The best fix for any nullability problems is to refactor the clients to use the Option<T?> approach I took in generichost. There is a difference between null and omitted, and each should be tracked separately. Unfortunately, this change is a lot of work. I don't think RestSharp nor HttpClient have contributors interested in doing this change. There are some vendor extensions that may be useful for a quick fix though.

x-is-value-type x-is-reference-type x-is-nullable-type -> is a value type or nrt is enabled

devhl-labs avatar Aug 10 '24 00:08 devhl-labs

For me the working workaround is to not yet use the DateOnly objects by setting the additionalProperty: --additional-properties=useDateTimeForDate=true

[https://openapi-generator.tech/docs/generators/aspnetcore/]

I have tried to add the extensions in the spec but that did not make the DateOnly property nullable for me

"active_till": { "type": "string", "format": "date", "readOnly": true, "nullable": true, "x-is-value-type": true },

resulted in

[DataMember(Name = "active_till", EmitDefaultValue = true)] public DateOnly ActiveTill { get; private set; }

Noudicus avatar Sep 13 '24 09:09 Noudicus