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

Unusable code for schema response with oneOf

Open aBMania opened this issue 1 year ago • 1 comments

Hello, I've looked for duplicate, but could not find exactly the same bug (as far as I searched), here are related ones:

  • https://github.com/oapi-codegen/oapi-codegen/issues/626
  • https://github.com/oapi-codegen/oapi-codegen/issues/1496
  • https://github.com/oapi-codegen/oapi-codegen/issues/1872
  • https://github.com/oapi-codegen/oapi-codegen/issues/1882
  • https://github.com/oapi-codegen/oapi-codegen/issues/1665

And a related PR:

  • https://github.com/oapi-codegen/oapi-codegen/pull/648

Steps to reproduce:

I've created minimal reproduction code here

1. OpenAPI Spec

openapi: 3.0.2
info:
  version: 1.0.0
  title: Issue 1900
paths:
  /ping:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Pong1'
                  - $ref: '#/components/schemas/Pong2'
                  - $ref: '#/components/schemas/Pong3'

2. Oapi-codegen config

package: issue1900
output: ping.gen.go
generate:
  models: true
  client: true

3. Generated code

type GetPingResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON200      *struct {
		union json.RawMessage
	}
	JSON404 *Error
}

Here the JSON200 type is unusable

Workaround

As a workaround, I've manually modified the OpenAPI spec of the API we are using before generating code:

# Changed:
'/Ping':
  get:
    # ...
    responses:
      '200':
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PongResponse"

# Added: 
  schemas:
    # ...
    PongResponse:
      oneOf:
        - $ref: "#/components/schemas/Pong1"
        - $ref: "#/components/schemas/Pong2"
        - $ref: "#/components/schemas/Pong3"
    # ...

And it's now generating a usable type:

type GetPingResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON200      *PongResponse  // generated type here
	JSON404      *Error
}
func (t PongResponse) AsPong1() (Pong1, error) { ... }
func (t PongResponse) AsPong2() (Pong2, error) { ... }
// ...

aBMania avatar Feb 12 '25 09:02 aBMania

I can confirm spending a couple hours on the same issue before looking here just now. My reproduction would have looked identical though.

PaluMacil avatar May 17 '25 11:05 PaluMacil