OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.34k stars 6.46k forks source link

[BUG] cshar .net6 DateOnly not nullable #18017

Open Noudicus opened 6 months ago

Noudicus commented 6 months ago

Bug Report Checklist

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": "api@test.com"
        },
        "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
0x326 commented 4 months ago

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";
        }
    }
MichaelMay81 commented 4 months ago

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

jpduchon commented 3 months ago

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?

alec-petersen commented 1 month ago

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?

devhl-labs commented 1 month ago

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

Noudicus commented 6 days ago

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; }