Carapacik / swagger_parser

Dart package that takes an OpenApi definition file and generates REST clients based on retrofit and data classes for your project.
https://pub.dev/packages/swagger_parser
MIT License
87 stars 33 forks source link

Add OpenAPI 3.1.0 enumeration style #121

Open theimmigrant-canada opened 8 months ago

theimmigrant-canada commented 8 months ago

In OpenAPI 3.1.0 there is a new method of enumerating things that allows us to have proper names for enumerations. Here is an example of that.

properties:
  LogLevel:
    type: integer
    oneOf:
      - title: Trace
        const: 0
        description: "A trace log level"
      - title: Debug
        const: 1
        description: "A debug log level"
      - title: Information
        const: 2
        description: "A information log level"

The main page of the project says that it supports OpenAPI 3.1 but this part still doesn't seem to be supported. Here is a thread on the subject

tfrancois commented 8 months ago

Let's fix this please. What will it take for it to be supported properly by Swagger (UI) and the like?

JohnGalt1717 commented 8 months ago

Or even x-ms-enum format which gives you the value that should be used, the name and description all of which can be used to generate an extended enum in Dart too. I.e. this

      "ArticleCategories": {
        "enum": [
          "Politics",
          "Sports",
          "Entertainment",
          "Finance",
          "Technology",
          "Travel",
          "Health",
          "Religion",
          "Science",
          "Education",
          "Environmental",
          "Lifestyle"
        ],
        "type": "string",
        "oneOf": [
          {
            "const": 1,
            "title": "Politics",
            "description": "Politics"
          },
          {
            "const": 2,
            "title": "Sports",
            "description": "Sports"
          },
          {
            "const": 4,
            "title": "Entertainment",
            "description": "Entertainment"
          },
          {
            "const": 8,
            "title": "Finance",
            "description": "Finance"
          },
          {
            "const": 16,
            "title": "Technology",
            "description": "Technology"
          },
          {
            "const": 32,
            "title": "Travel",
            "description": "Travel"
          },
          {
            "const": 64,
            "title": "Health",
            "description": "Health"
          },
          {
            "const": 128,
            "title": "Religion",
            "description": "Religion"
          },
          {
            "const": 256,
            "title": "Science",
            "description": "Science"
          },
          {
            "const": 512,
            "title": "Education",
            "description": "Education"
          },
          {
            "const": 1024,
            "title": "Environmental",
            "description": "Environmental"
          },
          {
            "const": 2048,
            "title": "Lifestyle",
            "description": "Lifestyle"
          }
        ]
      },

Should be able to generate this:

enum ArticleCategories {
  politics(1),
  sports(2),
  entertainment(4),
  finance(8),
  technology(16),
  travel(32),
  health(64),
  religion(128),
  science(256),
  education(512),
  environmental(1024),
  lifestyle(2048);

  const ArticleCategories(this.value);
  final int value;

  @override
  String toString() {
    switch (this) {
      case ArticleCategories.politics:
        return "Politics";
      case ArticleCategories.sports:
        return "Sports";
      case ArticleCategories.entertainment:
        return "Entertainment";
      case ArticleCategories.finance:
        return "Finance";
      case ArticleCategories.technology:
        return "Technology";
      case ArticleCategories.travel:
        return "Travel";
      case ArticleCategories.health:
        return "Health";
      case ArticleCategories.religion:
        return "Religion";
      case ArticleCategories.science:
        return "Science";
      case ArticleCategories.education:
        return "Education";
      case ArticleCategories.environmental:
        return "Environmental";
      case ArticleCategories.lifestyle:
        return "Lifestyle";
      default:
        throw UnimplementedError();
    }
  }
}

And of course it should be able to go further and have a get description accessor too.

JohnGalt1717 commented 8 months ago

Update, I have code that does this properly. It requires that the property have the enum array to be able to determine that it is indeed an enum.

If you'd like I can do a pull request and you can hack it up to meet your needs. This is what it produces (I don't have long descriptions only the name repeated):

// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint

import 'package:json_annotation/json_annotation.dart';

@JsonEnum()
enum ArticleCategories {
  /// Politics
  @JsonValue('1')
  politics('1'),

  /// Sports
  @JsonValue('2')
  sports('2'),

  /// Entertainment
  @JsonValue('4')
  entertainment('4'),

  /// Finance
  @JsonValue('8')
  finance('8'),

  /// Technology
  @JsonValue('16')
  technology('16'),

  /// Travel
  @JsonValue('32')
  travel('32'),

  /// Health
  @JsonValue('64')
  health('64'),

  /// Religion
  @JsonValue('128')
  religion('128'),

  /// Science
  @JsonValue('256')
  science('256'),

  /// Education
  @JsonValue('512')
  education('512'),

  /// Environmental
  @JsonValue('1024')
  environmental('1024'),

  /// Lifestyle
  @JsonValue('2048')
  lifestyle('2048');

  const ArticleCategories(this.json);

  final String? json;

  String? toJson() => json;

  @override
  String toString() {
    switch(this) {
        case ArticleCategories.politics:
          return "Politics";
        case ArticleCategories.sports:
          return "Sports";
        case ArticleCategories.entertainment:
          return "Entertainment";
        case ArticleCategories.finance:
          return "Finance";
        case ArticleCategories.technology:
          return "Technology";
        case ArticleCategories.travel:
          return "Travel";
        case ArticleCategories.health:
          return "Health";
        case ArticleCategories.religion:
          return "Religion";
        case ArticleCategories.science:
          return "Science";
        case ArticleCategories.education:
          return "Education";
        case ArticleCategories.environmental:
          return "Environmental";
        case ArticleCategories.lifestyle:
          return "Lifestyle";
    }
  }

  String toDescription() {
    switch(this) {
        case ArticleCategories.politics:
          return "Politics";
        case ArticleCategories.sports:
          return "Sports";
        case ArticleCategories.entertainment:
          return "Entertainment";
        case ArticleCategories.finance:
          return "Finance";
        case ArticleCategories.technology:
          return "Technology";
        case ArticleCategories.travel:
          return "Travel";
        case ArticleCategories.health:
          return "Health";
        case ArticleCategories.religion:
          return "Religion";
        case ArticleCategories.science:
          return "Science";
        case ArticleCategories.education:
          return "Education";
        case ArticleCategories.environmental:
          return "Environmental";
        case ArticleCategories.lifestyle:
          return "Lifestyle";
    }
  }

}
JohnGalt1717 commented 4 months ago

Bump: This is still broken and the enums it creates are "valueXXX" instead of proper names despite the fact that these are indeed available in the schema. It also doesn't properly override toString to return the proper values per the docs on new enums. It also doesn't set the name/value properly per new Dart enums so that it can have a numerical value associated with each item.

I'm specifically using dart_mappable, but any of them should generate similar to the above with a proper value and then simple name and then also be mappable to the value not the name for json.

JohnGalt1717 commented 1 week ago

I gave up on my pull request, but this is still a major blocker to this working correctly as it's basically impossible to use enums right now because you don't know which one is what.