-
-
Notifications
You must be signed in to change notification settings - Fork 1k
oneOf in nested RequestBody structure results in empty json #1882
Description
I believe this is similar to issue #970 but I can't be sure.
We have the following structure (some things have been removed for brevity):
openapi: 3.0.0
info:
title: WhatsApp API
description: >-
Internal API for WhatsApp.
version: 1.0.0
x-go-package: "github.com/oapi-codegen/runtime"
paths:
/v2/whatsapp:
post:
summary: Send a single WhatsApp message.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
content_type:
type: string
description: Type of the message content (e.g., template).
enum: [template]
content:
type: object
description: Content details for the message.
oneOf:
- $ref: '#/components/schemas/TemplateContent'
discriminator:
propertyName: object_type
required:
- content_type
- content
example:
content_type: "template"
content:
template:
name: "welcome_new_customer"
parameters: ["Joe"]
TemplateContent:
type: object
properties:
object_type:
type: string
template:
type: object
description: Template details for the message content.
properties:
name:
type: string
description: Name of the template used. Must be in lower case, alphanumeric characters, and underscore only.
parameters:
type: array
description: Values to be populated in the template.
items:
type: string
required:
- name
When unmarshalling the content inside the request body, it is empty. The patch in #970 is for responses only, I can have a go at the templating in a similar patch style as in that thread, but wanted to raise this bug as related
I attempted to manually fix this via creating what I think are the methods that are intended to be generated, based on the documentation, but I would like to confirm that before submitting any kind of patch
Generated successfully:
// TemplateContent defines model for TemplateContent.
type TemplateContent struct {
ObjectType string `json:"object_type"`
// Template Template details for the message content.
Template *struct {
// Name Name of the template used. Must be in lower case, alphanumeric characters, and underscore only.
Name string `json:"name"`
// Parameters Values to be populated in the template.
Parameters *[]string `json:"parameters,omitempty"`
} `json:"template,omitempty"`
}
// PostV2FoobarJSONBody defines parameters for PostV2Foobar.
type PostV2FoobarJSONBody struct {
// Content Content details for the message.
Content PostV2FoobarJSONBody_Content `json:"content"`
// ContentType Type of the message content (e.g., template).
ContentType PostV2FoobarJSONBodyContentType `json:"content_type"`
// From Registered Foobar sender number in international format.
From string `json:"from"`
// MessageRef Optional reference ID set by the user for the message.
MessageRef *string `json:"message_ref,omitempty"`
// To Recipient phone number in international format.
To string `json:"to"`
}
// PostV2FoobarJSONBody_Content defines parameters for PostV2Foobar.
type PostV2FoobarJSONBody_Content struct {
union json.RawMessage
}
// PostV2FoobarJSONBodyContentType defines parameters for PostV2Foobar.
type PostV2FoobarJSONBodyContentType string
// PostV2FoobarJSONRequestBody defines body for PostV2Foobar for application/json ContentType.
type PostV2FoobarJSONRequestBody PostV2FoobarJSONBody
Additional methods manually added
// AsTemplateContent returns the union data inside the PostV2FoobarJSONBody_Content as a TemplateContent
func (t PostV2FoobarJSONBody_Content) AsTemplateContent() (TemplateContent, error) {
var body TemplateContent
err := json.Unmarshal(t.union, &body)
return body, err
}
// FromTemplateContent overwrites any union data inside the PostV2FoobarJSONBody_Content as the provided TemplateContent
func (t *PostV2FoobarJSONBody_Content) FromTemplateContent(v TemplateContent) error {
b, err := json.Marshal(v)
t.union = b
return err
}
// MergeTemplateContent performs a merge with any union data inside the PostV2FoobarJSONBody_Content, using the provided TemplateContent
func (t *PostV2FoobarJSONBody_Content) MergeTemplateContent(v TemplateContent) error {
b, err := json.Marshal(v)
if err != nil {
return err
}
merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
func (t PostV2FoobarJSONBody_Content) MarshalJSON() ([]byte, error) {
b, err := t.union.MarshalJSON()
return b, err
}
func (t *PostV2FoobarJSONBody_Content) UnmarshalJSON(b []byte) error {
err := t.union.UnmarshalJSON(b)
return err
}
I then used it like so (added a Discriminator)
bodyContent, err := body.Content.ValueByDiscriminator()
if err != nil {
return nil, err
}
discriminator, err := body.Content.Discriminator()
// This seems long winded but if we want to use it, it needs casting to the correct type, and if we want it adding to the full bodyRequest, then marshalling into the 'union' type.
if discriminator == "TemplateContent" {
v, ok := bodyContent.(openapi.TemplateContent)
if !ok {
panic("oops")
}
err = body.Content.FromTemplateContent(v)
if err != nil {
return nil, fmt.Errorf("failed to merge TemplateContent to body content: %w", err)
}
}
if discriminator == "FoobarContent" {
v, ok := bodyContent.(openapi.FoobarContent)
if !ok {
panic("oops")
}
err = body.Content.FromFoobarContent(v)
if err != nil {
return nil, fmt.Errorf("failed to merge FoobarContant to body content: %w", err)
}
}
So two questions, is the missing methods a bug, and which template should I concentrate on for a patch?
and
When the methods are in place, is that the right way to use it? It's a bit long winded, which is fine but want to be sure.