Skip to content

bug: MarshalJSON (and UnmarshalJSON) are not generated for the ResponseObject when the response is a oneOf schema #1665

@akishichinibu

Description

@akishichinibu
❯ go version
go version go1.22.1 darwin/arm64
❯ oapi-codegen --version
github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
v2.3.0

Hi👋 , I think there's a bug in oapi-codegen v2.3.0 and there's a minimal example to reproduce the problem

oapi-codegen -config config.yaml test.yaml

config.yaml

# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: "api"
generate:
  echo-server: true
  models: true
  strict-server: true
  embedded-spec: false
output: api.gen.go
output-options:
  nullable-type: true
  initialism-overrides: true

test.yaml

openapi: 3.0.3
info:
  title: Swagger Petstore - OpenAPI 3.0
  version: 1.0.11
paths:
  /pet/findByStatus:
    get:
      tags:
        - pet
      summary: Finds Pets by status
      description: Multiple status values can be provided with comma separated strings
      operationId: findPetsByStatus
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PP'
components:
  schemas:
    Pet1:
      type: object
      properties:
        id:
          type: integer
          format: int64
          example: 10
        name:
          type: string
          example: doggie
    Pet2:
      type: object
      properties:
        id:
          type: integer
          format: int64
          example: 10
        name:
          type: string
          example: doggie
    PP:
      type: object
      oneOf:
        - "$ref": "#/components/schemas/Pet1"
        - "$ref": "#/components/schemas/Pet2"

Part of the generated server code

type PP struct {
	union json.RawMessage
}

func (t PP) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

func (t *PP) UnmarshalJSON(b []byte) error {
	err := t.union.UnmarshalJSON(b)
	return err
}

type FindPetsByStatusResponseObject interface {
	VisitFindPetsByStatusResponse(w http.ResponseWriter) error
}

type FindPetsByStatus200JSONResponse PP

func (response FindPetsByStatus200JSONResponse) VisitFindPetsByStatusResponse(w http.ResponseWriter) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)

	return json.NewEncoder(w).Encode(response)
}

The MarshalJSON was generated correctly for PP but NOT for the response object in strict-server mode.
Because there's only one private member union in PP, when the user try to return a FindPetsByStatusResponseObject in handler like the code below

var p PP
p.FromPet1(...)
return FindPetsByStatus200JSONResponse(p), nil

the responseObject will be marshal to an empty JSON.

I think an additional MarshalJSON(and UnmarshalJSON) should be generated when the response is a oneOf schema.

func (t FindPetsByStatus200JSONResponse) MarshalJSON() ([]byte, error) {
	b, err := t.union.MarshalJSON()
	return b, err
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions