oapi-codegen icon indicating copy to clipboard operation
oapi-codegen copied to clipboard

Issue generating enum in paths

Open vishen opened this issue 3 years ago • 5 comments

I may be doing something wrong, or using it wrong, but I am getting errors when generating the HTTP client with the following openapi spec:

# openapi.yaml

openapi: 3.0.0
info:
  description: example
  title: example-api
  version: 0.0.1
paths:
  '/path':
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - online
                      - offline
                    example: 'online'
components:
  schemas: {}

Using master, I generate this with: go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -package=clients -generate=client,types -o http.gen.go openapi.yaml

And that generates the following Go code:

...
type GetPathResponse struct {
        Body         []byte
        HTTPResponse *http.Response
        JSON200      *struct {
                Status *N200Status `json:"status,omitempty"`
        }
}
...

However N200Status doesn't exist as a type, it hasn't been generated for some reason. Prior to https://github.com/deepmap/oapi-codegen/pull/241 it used to generate it as:

type GetPathResponse struct {
        Body         []byte
        HTTPResponse *http.Response
        JSON200      *struct {
                Status *string `json:"status,omitempty"`
        }
}

I think the issue might be because enum types are only generated for swagger.Components but this enum is on swagger.Paths: https://github.com/deepmap/oapi-codegen/blob/master/pkg/codegen/codegen.go#L301-L304

I am able to get around this issue by moving the enum into the components section which will then generate all the types:

openapi: 3.0.0
info:
  description: example
  title: example-api
  version: 0.0.1
paths:
  '/path':
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Response'
components:
  schemas:
    Response:
      type: object
      properties:
        status:
          type: string
          enum:
            - online
            - offline
          example: 'online'

Just wondering if this expected behaviour and if I should always put everything in the components section?

vishen avatar Jul 07 '21 01:07 vishen

Same problem with enum parameters

foxcool avatar Aug 16 '21 08:08 foxcool

Thank you for the issue, have the same problem

mariaefi29 avatar Jan 13 '22 09:01 mariaefi29

Thank you @vishen. This is a very helpful discovery. I ended up applying this to the OpenAPI 3.0 spec for Tenable.io's Platform API.

I documented my process and thinking here in case it may be useful for other folks consuming vendor APIs they don't control: https://gist.github.com/alain-odea-sequence/54d479d68693d0e99c907ca699a6ebd7

alain-odea-sequence avatar Jun 26 '22 18:06 alain-odea-sequence

The bug in codegen with enums is way more subtle than it seems. It's mostly correct, is missing two major components:

  1. GenerateTypesForPaths doesn't exist so there's no possibility of a type in a path definition being captured
  2. GenerateEnums doesn't search the tree of an object schema for enum TypeDefinitions

This block of code does a depth 1 collection of TypeDefinitions that are enums: https://github.com/deepmap/oapi-codegen/blob/14fc88e236ce62c1d280904e7670b4226f02da31/pkg/codegen/codegen.go#L581-L600

I have a super-naive start on GenerateTypesForPaths:

// GenerateTypesForPaths generates type definitions for any custom types defined in the
// paths section of the Swagger spec.
func GenerateTypesForPaths(t *template.Template, paths openapi3.Paths) ([]TypeDefinition, error) {
	var types []TypeDefinition

	for _, pathName := range SortedPathsKeys(paths) {
		path := paths[pathName]

		get := path.Get
		paramsMap := make(openapi3.ParametersMap)
		for _, param := range get.Parameters {
			paramsMap[param.Ref] = param
		}
		parameterTypes, err := GenerateTypesForParameters(t, paramsMap)
		if err != nil {
			return types, err
		}
		types = append(types, parameterTypes...)

		responses := get.Responses
		responsesTypes, err := GenerateTypesForResponses(t, responses)
		types = append(types, responsesTypes...)
	}

	return types, nil
}

I'm going to try to put together a PR for this. I think it will close an apparently large gap with a fairly small amount of change.

alain-odea-sequence avatar Jun 30 '22 19:06 alain-odea-sequence

I have what I think is a working PR for this in #654. It passes the test suite and I have yet to identify a scenario with enums that it misses. I haven't done anything truly exotic with it to bend its limits, but it's able to generate lot more the Tenable.io Platform API out of the box from their OpenAPI 3.0 specs now.

AlainODea avatar Jul 01 '22 23:07 AlainODea

I hit this problem when trying to generate a client for https://github.com/SpaceTradersAPI/api-docs/blob/main/reference/SpaceTraders.json

I get many types such as N200DataTraitsSymbol which are not generated. This symbol refers to a declaration like https://github.com/SpaceTradersAPI/api-docs/blob/main/models/FactionTrait.json#L4

Dutchy- avatar May 09 '23 17:05 Dutchy-