swagger_parser icon indicating copy to clipboard operation
swagger_parser copied to clipboard

Optional properties in requests are generated as being required

Open JeongJuhyeon opened this issue 9 months ago • 4 comments

Steps to reproduce

This is partially due to https://github.com/Carapacik/swagger_parser/pull/252, though even without it, the problem still exists as the properties would be getting sent as null instead of omitted.

I made a basic PR, it may need work: http://github.com/Carapacik/swagger_parser/pull/308

Expected results

  1. No required in constructor
@JsonSerializable()
class Object0 {
  const Object0({
    required this.name,
    required this.age,
    this.hobby,
  });
  1. Omit the property if it's null:
  @JsonKey(includeIfNull: false)
  final String? hobby;

Actual results

@JsonSerializable()
class Object0 {
  const Object0({
    required this.name,
    required this.age,
    required this.hobby,
  });
  
  factory Object0.fromJson(Map<String, Object?> json) => _$Object0FromJson(json);
  
  /// The user's name
  final String name;

  /// The user's age
  final int age;

  /// The user's hobby (optional)
  final String hobby;

  Map<String, Object?> toJson() => _$Object0ToJson(this);
}

Your OpenApi snippet

{
  "openapi": "3.0.0",
  "info": {
    "title": "Simple User API",
    "version": "1.0.0"
  },
  "paths": {
    "/user": {
      "post": {
        "summary": "Create a new user",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "age"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The user's name"
                  },
                  "age": {
                    "type": "integer",
                    "description": "The user's age"
                  },
                  "hobby": {
                    "type": "string",
                    "description": "The user's hobby (optional)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created successfully"
          }
        }
      }
    }
  }
}

Code sample

No response

Logs

No response

Dart version and used packages versions

Latest.

JeongJuhyeon avatar Mar 23 '25 13:03 JeongJuhyeon

i have the same problem this example schema

"schemas": {
      "MenuItem": {
        "type": "object",
        "required": ["title"],
        "properties": {
          "title": { "type": "string", "example": "Test 123" },
          "title2": { "type": "string", "example": "Test 123" }
        }
      }
    }

is generated with freezed into:

@Freezed()
class MenuItem with _$MenuItem {
  const factory MenuItem({
    required String title,
    required String title2,
  }) = _MenuItem;
  
  factory MenuItem.fromJson(Map<String, Object?> json) => _$MenuItemFromJson(json);
}

whereas title2 is also required, which is wrong because it can be missed out

winren9 avatar Mar 24 '25 06:03 winren9

This should be fixed since v1.24.4, if I understand correctly?

Peetee06 avatar Jul 27 '25 05:07 Peetee06

We're also experiencing this issue on packages beyond 1.25.0 and up. 1.24.0 up to 1.25.0 gives us invalid output

So our current latest working version is 1.23.2 that generates correct output and respects nullability on parameters.

This is the snippet that results in required parameters on version 1.28.0:

"BookBookingLinkEventPublicRequest": {
        "type": "object",
        "properties": {
          "bookingLinkId": {
            "type": "integer",
            "format": "int64"
          },
          "startTime": {
            "type": "string",
            "format": "date-time"
          },
          "endTime": {
            "type": "string",
            "format": "date-time"
          },
          "additionalParticipant": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ParticipantAddModel"
              }
            ],
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },

will generate

@JsonSerializable()
class BookBookingLinkEventPublicRequest {
  const BookBookingLinkEventPublicRequest({
    required this.bookingLinkId,
    required this.startTime,
    required this.endTime,
    required this.additionalParticipant,
    required this.title,
    required this.description,
  });
  
  factory BookBookingLinkEventPublicRequest.fromJson(Map<String, Object?> json) => _$BookBookingLinkEventPublicRequestFromJson(json);
  
  final int bookingLinkId;
  final DateTime startTime;
  final DateTime endTime;
  final ParticipantAddModel additionalParticipant;
  final String? title;
  final String? description;

  Map<String, Object?> toJson() => _$BookBookingLinkEventPublicRequestToJson(this);
}

Our other dependencies are:

  json_serializable: 6.9.5
  retrofit_generator: 9.2.0

cverhelst avatar Aug 07 '25 09:08 cverhelst

I have just posted a similar issue. Seems to be a bug in handling nullable allOf?

ObviouslyRichB avatar Aug 07 '25 16:08 ObviouslyRichB