-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[core][go] Generate inline models that were not previously generated #3162
Conversation
…to inline-resolver * 'master' of github.com:OpenAPITools/openapi-generator: (213 commits) Idiomatic Rust returns for Error conversions (OpenAPITools#2812) Add API timeout handling (OpenAPITools#3078) Import inner items for map (OpenAPITools#3123) update core team in pom.xml (OpenAPITools#3126) [gradle] Document consuming via gradle plugin portal (OpenAPITools#3125) Bump up babel-cli version to fix security alert (OpenAPITools#3121) [C++] [cpprestsdk] Add examples and test for cpprestsdk (OpenAPITools#3109) Add enum support to `rust` and skip none option serialization in clients (OpenAPITools#2244) Add/update new core team member: etherealjoy (OpenAPITools#3116) Gradle sample on travis (OpenAPITools#3114) [typescript-fetch] add bearer token support (OpenAPITools#3097) Add Q_DECLARE_METATYPE to the generated models and remove ref in signals (OpenAPITools#3091) [Java][okhttp-gson] Update dependencies (OpenAPITools#3103) Link query parameter to model object (OpenAPITools#2710) scala-play-server: fix enum names for reserved words (OpenAPITools#3080) Add @Sunn to openapi generator core team (OpenAPITools#3105) fix NPE in go generator (OpenAPITools#3104) scala-play-server: fix API doc url (OpenAPITools#3096) [maven-plugin] fix strictSpec parameter without alias (OpenAPITools#3095) Ruby: Avoid double escaping path items (OpenAPITools#3093) ... # Conflicts: # modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java # modules/openapi-generator/src/test/java/org/openapitools/codegen/InlineModelResolverTest.java
👍 Thanks for opening this issue! The team will review the labels and make any necessary changes. |
Would love to get approval of this approach before I start fixing tests (which I am happy to do) cc core team: |
Can you explain more how this handles more than one schema? In the example, In the Example Spec: Cat:
type: object
properties:
myTaxonomy:
anyOf: # inline anyOf
- $ref: '#/components/schemas/Species'
- $ref: '#/components/schemas/Order' Example Generated Code: type CatMyTaxonomy struct {
Name string `json:"name"`
} Here are some example schema definitions for
Species:
description: Referenced schema
type: object
properties:
name:
type: string
genus:
type: string
karyotype:
type: string
Order:
description: Referenced schema
type: object
properties:
name:
type: string
class:
type: string |
Good call @grokify - the example I gave didn't do a good job of demonstrating the change, let me try and rework it to be fully inline. For your specific question about components:
schemas:
CatMyTaxonomy:
anyOf: # inline anyOf
- $ref: '#/components/schemas/Species'
- $ref: '#/components/schemas/Order'
Cat:
type: object
properties:
myTaxonomy:
- $ref: '#/components/schemas/CatMyTaxonomy' So I'm not changing anything about how The missing referenced schemas are:
Yes indeed, the key to the change I've made is that the
So just updating the example to use these for Species and Order: Species:
description: Referenced schema
type: object
properties:
name:
type: string
genus:
type: string
karyotype:
type: string
Order:
description: Referenced schema
type: object
properties:
name:
type: string
class:
type: string Yields the following output which is consistent with how the go generator already does anyOf (a struct that is the union of all properties):
type CatMyTaxonomy struct {
Name string `json:"name,omitempty"`
Genus string `json:"genus,omitempty"`
Karyotype string `json:"karyotype,omitempty"`
Class string `json:"class,omitempty"`
} while still outputting the // Referenced schema
type Species struct {
Name string `json:"name,omitempty"`
Genus string `json:"genus,omitempty"`
Karyotype string `json:"karyotype,omitempty"`
}
// Referenced schema
type Order struct {
Name string `json:"name,omitempty"`
Class string `json:"class,omitempty"`
} |
@grokify I updated the example in the PR description to have multiple entries in the |
Thanks for the update. Much clearer. The following should be namespaced to prevent collisions. Other than that it looks reasonable to me. // Note: Go doesn't currently support complex additionalProperties, but this model is still generated:
type Metadata string
// List of Metadata
const (
METADATA_HIDDEN Metadata = "hidden"
METADATA_CREATED_ON Metadata = "createdOn"
METADATA_CREATED_BY Metadata = "createdBy"
METADATA_MODIFIED_ON Metadata = "modifiedOn"
METADATA_MODIFIED_BY Metadata = "modifiedBy"
) Perhaps something similar to what you have for // List of Metadata
const (
CAT_PREFERENCES_METADATA_HIDDEN Metadata = "hidden"
CAT_PREFERENCES_METADATA_CREATED_ON Metadata = "createdOn"
CAT_PREFERENCES_METADATA_CREATED_BY Metadata = "createdBy"
CAT_PREFERENCES_METADATA_MODIFIED_ON Metadata = "modifiedOn"
CAT_PREFERENCES_METADATA_MODIFIED_BY Metadata = "modifiedBy"
) |
Update InlineModelResolverTest to use more illustrative inline models.
Great feedback, @grokify I have updated the namespacing such that this is now generated: type CatPreferencesMetadata string
// List of CatPreferencesMetadata
const (
CAT_PREFERENCES_METADATA_HIDDEN CatPreferencesMetadata = "hidden"
CAT_PREFERENCES_METADATA_CREATED_ON CatPreferencesMetadata = "createdOn"
CAT_PREFERENCES_METADATA_CREATED_BY CatPreferencesMetadata = "createdBy"
CAT_PREFERENCES_METADATA_MODIFIED_ON CatPreferencesMetadata = "modifiedOn"
CAT_PREFERENCES_METADATA_MODIFIED_BY CatPreferencesMetadata = "modifiedBy"
) also updated the Let me know if there's anything else needed. |
I think the work in this PR may resolve some issues around Enum handling. The biggest issue I see is that it results in a breaking issue for consumers of existing clients for every client that supports enums. Take, for instance, this one change of a csharp client generated against this branch: diff --git a/samples/client/petstore/csharp/OpenAPIClientNetStandard/src/Org.OpenAPITools/Model/EnumArrays.cs b/samples/client/petstore/csharp/OpenAPIClientNetStandard/src/Org.OpenAPITools/Model/EnumArrays.cs
index 4c0e96fd21..0f588412bb 100644
--- a/samples/client/petstore/csharp/OpenAPIClientNetStandard/src/Org.OpenAPITools/Model/EnumArrays.cs
+++ b/samples/client/petstore/csharp/OpenAPIClientNetStandard/src/Org.OpenAPITools/Model/EnumArrays.cs
@@ -28,69 +28,28 @@ namespace Org.OpenAPITools.Model
[DataContract]
public partial class EnumArrays : IEquatable<EnumArrays>
{
- /// <summary>
- /// Defines JustSymbol
- /// </summary>
- [JsonConverter(typeof(StringEnumConverter))]
- public enum JustSymbolEnum
- {
- /// <summary>
- /// Enum GreaterThanOrEqualTo for value: >=
- /// </summary>
- [EnumMember(Value = ">=")]
- GreaterThanOrEqualTo = 1,
-
- /// <summary>
- /// Enum Dollar for value: $
- /// </summary>
- [EnumMember(Value = "$")]
- Dollar = 2
-
- }
-
/// <summary>
/// Gets or Sets JustSymbol
/// </summary>
[DataMember(Name="just_symbol", EmitDefaultValue=false)]
- public JustSymbolEnum? JustSymbol { get; set; }
- /// <summary>
- /// Defines ArrayEnum
- /// </summary>
- [JsonConverter(typeof(StringEnumConverter))]
- public enum ArrayEnumEnum
- {
- /// <summary>
- /// Enum Fish for value: fish
- /// </summary>
- [EnumMember(Value = "fish")]
- Fish = 1,
-
- /// <summary>
- /// Enum Crab for value: crab
- /// </summary>
- [EnumMember(Value = "crab")]
- Crab = 2
-
- }
-
-
- /// <summary>
- /// Gets or Sets ArrayEnum
- /// </summary>
- [DataMember(Name="array_enum", EmitDefaultValue=false)]
- public List<ArrayEnumEnum> ArrayEnum { get; set; }
+ public EnumArraysJustSymbol? JustSymbol { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="EnumArrays" /> class.
/// </summary>
/// <param name="justSymbol">justSymbol.</param>
/// <param name="arrayEnum">arrayEnum.</param>
- public EnumArrays(JustSymbolEnum? justSymbol = default(JustSymbolEnum?), List<ArrayEnumEnum> arrayEnum = default(List<ArrayEnumEnum>))
+ public EnumArrays(EnumArraysJustSymbol justSymbol = default(EnumArraysJustSymbol), List<EnumArraysArrayEnumItems> arrayEnum = default(List<EnumArraysArrayEnumItems>))
{
this.JustSymbol = justSymbol;
this.ArrayEnum = arrayEnum;
}
+ /// <summary>
+ /// Gets or Sets ArrayEnum
+ /// </summary>
+ [DataMember(Name="array_enum", EmitDefaultValue=false)]
+ public List<EnumArraysArrayEnumItems> ArrayEnum { get; set; }
/// <summary>
/// Returns the string presentation of the object Enums defined as inline are no longer inlined (see
As both an author and consumer of this document, I'd expect an object called That said, I'm wondering how hard would it be to have this enum promotion logic as opt-in behind a generation flag? Or, could it be added as another generation option (on CodegenConfig) which generators must override in order to opt-in to the model shuffling? I believe @jmini has done a lot of work on the inline model resolver, and may have additional comments. |
@@ -64,7 +65,11 @@ private void flattenPaths(OpenAPI openAPI) { | |||
|
|||
for (String pathname : paths.keySet()) { | |||
PathItem path = paths.get(pathname); | |||
for (Operation operation : path.readOperations()) { | |||
List<Operation> ops = path.readOperations(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nbd, but path.readOperations()
will never return null.
@jimschubert I see what you mean, including the inline enum within the C# model files was intentional. What I've observed is that many (most?) languages don't have separate templating support for inline enums, they work for enums that have been promoted to the I think it would be pretty simple to add a flag (and perhaps adjust the default behavior for C# and Typescript and other languages that already support inline enums) such that enums are not promoted to their own schema under |
was this PR abandon? |
…esolver # Conflicts: # modules/openapi-generator/src/main/java/org/openapitools/codegen/InlineModelResolver.java # samples/client/petstore/dart2/openapi/lib/api/pet_api.dart # samples/client/petstore/dart2/openapi/lib/api/store_api.dart # samples/client/petstore/dart2/openapi/lib/api/user_api.dart # samples/client/petstore/dart2/openapi/lib/api_client.dart # samples/client/petstore/ruby-faraday/lib/petstore/models/test_enum_parameters_body.rb # samples/client/petstore/ruby-faraday/lib/petstore/models/upload_file_with_required_file_body.rb # samples/client/petstore/ruby/lib/petstore/models/test_endpoint_parameters_body.rb # samples/client/petstore/ruby/lib/petstore/models/test_json_form_data_body.rb # samples/client/petstore/ruby/lib/petstore/models/update_pet_with_form_body.rb # samples/client/petstore/ruby/lib/petstore/models/upload_file_body.rb # samples/client/petstore/ruby/spec/models/test_endpoint_parameters_body_spec.rb # samples/client/petstore/ruby/spec/models/upload_file_body_spec.rb # samples/openapi3/client/petstore/ruby-faraday/spec/models/tag_spec.rb # samples/openapi3/client/petstore/ruby/spec/models/test_enum_parameters_body_spec.rb # samples/openapi3/client/petstore/ruby/spec/models/test_json_form_data_body_spec.rb # samples/openapi3/client/petstore/ruby/spec/models/upload_file_body_spec.rb # samples/schema/petstore/mysql/mysql_schema.sql
I fixed the issues with Ruby samples, the samples were just out of date and referencing deleted files. |
Moving on to Go samples failures next. I feel like I'm close? But I also feel like every day an eagle swoops down and eats my liver. |
@fantavlik thanks for leading the effort to improve the inline model resolver. How urgent do you need this change to be included in the next release v5.0.1 (we'll release v5.0.0 within hours)? If it's not urgent, may I suggest putting this PR on hold for the time being while the core team performs another review in early or mid Jan? |
I have been dragging my feet on this but I finally have some more time now and moving forward, I am happy to wait to January. |
👌 thanks again for the PR. Happy holidays! |
Same to you William! Looking forward to finishing this up in the new year. |
@fantavlik Thank you for working on this, I have been following this PR for a while and I am keen to see it get merged. Please let me know if there is anything I can do to help. Happy to test out your branch against a bunch of openapi specs that are used in production. |
Same, keen to see this landed - Rust doesn't support anonymous, or inline enums. Let me know if you need any help getting this landed. |
If/when this is landed, will there be a flag to turn off strict validation of enum values for languages where they are not currently validated? Otherwise this seems like a potentially breaking change. |
Any update on this? I am generating go models from an api spec from a third party and would really like the added safety of typed enums. Please let me know if there is anything I can do to help get this merged. |
Hi, is there any updates on this PR? thanks for the hard work, this is really important for me. |
It looks like this issue has been a can kicked down the road for the last 4 years. @fantavlik you've put a lot of work into this but it looks like the tests are still a blocking issue. Are you still actively invested in this PR? It looks like from the history on this issue the main problem has been fragmented test failures with the different languages. Would it help if we could split the PR into the different language slices so we can piece meal merge the support in for each language that works? For the ones that still have issues we could let contributors with those language needs/expertise help with the test issues. Perhaps that would help avoid letting perfection become the enemy of progress? |
Hey all, glad there's is still interest in this and sorry I abandoned this 3 years ago - I'm in a better place now personally to try to get this merged but want to make sure @wing328 and any other maintainers still support moving forward with this before I dig in again. @codyolsen I had hoped to originally do what you suggest and break the PR apart by language but InlineModelResolver.java affects the inputs to all language templates. I guess one option would be to leave the existing InlineModelResolver.java code in place and feature flag the refactored resolver to allow languages to opt-in. @wing328 let me know if that's something you are open to. |
Hi all, we've merged a few PRs to improve inline schema handling: https://github.com/OpenAPITools/openapi-generator/pulls?q=is%3Apr+inline+schema+is%3Aclosed+author%3Awing328 Thanks @fantavlik for this PR as a staring point 🙏 We still haven't added an option to generate all enum as models. Hopefully it will be something we can support in 7.x or later. |
Hi all, |
@wing328 That's great there has been some progress on inline schema handling! Is there a way that we can merge in what @fantavlik has done on this CR to compliment the changes? |
@longquanzheng That works if you have control of the model, but if it's a 3rd party schema you can't control then you are out of luck. |
that's done in latest master (upcoming v7.0.0 release) |
closing this one as pretty much all enhancements are added to the master thanks again for this PR as a starting point. |
Description of the PR
Core Changes
Examples of inline schemas that were not being generated that need their own models: enums, objects with defined properties, and composed schemas.
Examples of inline locations that are now being checked recursively for inline models: within object properties, within object additionalProperties, within definitions of composed schemas (similar approach to Better handling of inline composed schemas in InlineModelResolver #2112), within definitions of "not", and within array items.
Items
suffix, etc. Schemas with "title" fields will still use the title if defined.Go changes (affecting all Go-based generators as changes were made within AbstractGoCodegen.java)
This is a followup from #2494 - I attempted to fix this issue using Go templates at first but realized that a core change could fix these kinds of issues across all languages by refactoring the InlineModelResolver.java.
This also takes the support added by #2112 and extends that implementation to be recursive
(I changed the suffixes slightly to bethe suffixes now matchAllOf
, rather than_allOf
but otherwise the support should be the same)AllOf
,OneOf
,AnyOf
since this seems like the better convention.Models like this which have many inline schemas that should be resolved into their own separate schemas/models were losing information (e.g. declaring enums as simple strings or declaring arrays of models arrays of simple objects).
Example:
Sample output before these changes (Go):
New output (Go):
I've only regenerated samples for Go so far but pretty much every language will have new models defined that were missing before.