Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • O openapi-generator
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 3,476
    • Issues 3,476
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 402
    • Merge requests 402
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • OpenAPI Tools
  • openapi-generator
  • Merge requests
  • !3162

[core][go] Generate inline models that were not previously generated

  • Review changes

  • Download
  • Email patches
  • Plain diff
Open Administrator requested to merge github/fork/fantavlik/inline-resolver into master Jun 17, 2019
  • Overview 0
  • Commits 62
  • Pipelines 1
  • Changes 482+

Created by: fantavlik

Description of the PR

Core Changes

  • Refactor InlineModelResolver.java to recursively identify inline schemas that require their own model definitions. 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 https://github.com/OpenAPITools/openapi-generator/pull/2112), within definitions of "not", and within array items.
  • Add more contextual naming rather than InlineObject, schemas defined inline within an operation section will get prefixes with the operation id, schemas within an array items section will get the parent model name + 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)

  • Prefix all enum values with model name, this is needed to avoid collisions within the package
  • Fix issue where numerical enums were quoted
  • Fix issue where numerical enums would begin with underscore

This is a followup from https://github.com/OpenAPITools/openapi-generator/pull/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 https://github.com/OpenAPITools/openapi-generator/pull/2112 and extends that implementation to be recursive (I changed the suffixes slightly to be AllOf, rather than _allOf but otherwise the support should be the same) the suffixes now match 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:

Cat:
  description: Complex model with many inline models defined within it.
  type: object
  properties:
    myFood:
      oneOf: # inline oneOf
        - type: object
          title: Food
          properties:
            ingredients:
              type: array
              items:
                type: string
            pounds:
              type: integer
          required:
            - fooProp
    myHabitat:
      allOf: # inline allOf
        - type: object
          title: HabitatGeography
          properties:
            lat:
              type: number
              format: float
            long:
              type: number
              format: float
            continent:
              type: string
              enum:
                - Africa
                - Antarctica
                - Asia
                - Europe
                - North America
                - Oceania
                - South America
          required: [lat, long]
        - type: object
          description: Weather of the habitat defined here
          properties:
            rainfallInches:
              type: number
            averageTemperatureCelsius:
              type: number
    myTaxonomy:
      anyOf: # inline anyOf
        - description: Referenced schema
          type: object
          title: Species
          properties:
            name:
              type: string
            genus:
              type: string
            karyotype:
              type: string
        - description: Referenced schema
          type: object
          title: Order
          properties:
            name:
              type: string
            class:
              type: string
    cuteness: # inline enum
      type: integer
      enum: [1,3,5]
    kittens:
      type: array
      items: # inline array where the items are inline models
        allOf:
          - $ref: '#/components/schemas/Cat'
    preferences:
      type: object
      properties:
        favoriteToy: # inline object with properties defined
          type: string
      additionalProperties: # inline object with additionalProperties containing inline models
        title: Metadata
        type: string
        enum: [hidden,createdOn,createdBy,modifiedOn,modifiedBy]

Sample output before these changes (Go):

// Complex model with many inline models defined within it.
type Cat struct {
	MyFood OneOfobject `json:"myFood,omitempty"`
	MyHabitat map[string]interface{} `json:"myHabitat,omitempty"`
	MyTaxonomy AnyOfobjectobject `json:"myTaxonomy,omitempty"`
	Cuteness int32 `json:"cuteness,omitempty"`
	Kittens []Cat `json:"kittens,omitempty"`
	Preferences map[string]string `json:"preferences,omitempty"`
}
...
// OneOfobject does not exist - not generated
// AnyOfobjectobject does not exist - not generated

New output (Go):

// Complex model with many inline models defined within it.
type Cat struct {
	MyFood CatMyFood `json:"myFood,omitempty"`
	MyHabitat CatMyHabitat `json:"myHabitat,omitempty"`
	MyTaxonomy CatMyTaxonomy `json:"myTaxonomy,omitempty"`
	Cuteness CatCuteness `json:"cuteness,omitempty"`
	Kittens []CatKittensItems `json:"kittens,omitempty"`
	Preferences CatPreferences `json:"preferences,omitempty"`
}
...
type CatMyFood struct {
	Ingredients []string `json:"ingredients,omitempty"`
	Pounds int32 `json:"pounds,omitempty"`
}
...
type CatMyHabitat struct {
	Lat float32 `json:"lat"`
	Long float32 `json:"long"`
	Continent CatMyHabitatAllOfContinent `json:"continent,omitempty"`
	RainfallInches float32 `json:"rainfallInches,omitempty"`
	AverageTemperatureCelsius float32 `json:"averageTemperatureCelsius,omitempty"`
}
...
type CatMyHabitatAllOfContinent string

// List of CatMyHabitatAllOfContinent
const (
	CAT_MY_HABITAT_ALL_OF_CONTINENT_AFRICA CatMyHabitatAllOfContinent = "Africa"
	CAT_MY_HABITAT_ALL_OF_CONTINENT_ANTARCTICA CatMyHabitatAllOfContinent = "Antarctica"
	CAT_MY_HABITAT_ALL_OF_CONTINENT_ASIA CatMyHabitatAllOfContinent = "Asia"
	CAT_MY_HABITAT_ALL_OF_CONTINENT_EUROPE CatMyHabitatAllOfContinent = "Europe"
	CAT_MY_HABITAT_ALL_OF_CONTINENT_NORTH_AMERICA CatMyHabitatAllOfContinent = "North America"
	CAT_MY_HABITAT_ALL_OF_CONTINENT_OCEANIA CatMyHabitatAllOfContinent = "Oceania"
	CAT_MY_HABITAT_ALL_OF_CONTINENT_SOUTH_AMERICA CatMyHabitatAllOfContinent = "South America"
)
...
type CatMyTaxonomy struct {
	Name string `json:"name,omitempty"`
	Genus string `json:"genus,omitempty"`
	Karyotype string `json:"karyotype,omitempty"`
	Class string `json:"class,omitempty"`
}
...
type CatCuteness int32

// List of CatCuteness
const (
	CAT_CUTENESS_1 CatCuteness = 1
	CAT_CUTENESS_3 CatCuteness = 3
	CAT_CUTENESS_5 CatCuteness = 5
)
...
type CatKittensItems struct {
	MyFood CatMyFood `json:"myFood,omitempty"`
	MyHabitat CatMyHabitat `json:"myHabitat,omitempty"`
	MyTaxonomy CatMyTaxonomy `json:"myTaxonomy,omitempty"`
	Cuteness CatCuteness `json:"cuteness,omitempty"`
	Kittens []CatKittensItems `json:"kittens,omitempty"`
	Preferences CatPreferences `json:"preferences,omitempty"`
}
...
type CatPreferences struct {
	FavoriteToy string `json:"favoriteToy,omitempty"`
}
...
// Note: Go doesn't currently support complex additionalProperties, but this model is still 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"
)

I've only regenerated samples for Go so far but pretty much every language will have new models defined that were missing before.

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: github/fork/fantavlik/inline-resolver