diff --git a/internal/test/anonymous_inner_hoisting/cfg.yaml b/internal/test/anonymous_inner_hoisting/cfg.yaml new file mode 100644 index 0000000000..bbdee926a3 --- /dev/null +++ b/internal/test/anonymous_inner_hoisting/cfg.yaml @@ -0,0 +1,5 @@ +package: anonymous_inner_hoisting +output: client.gen.go +generate: + models: true + client: true diff --git a/internal/test/anonymous_inner_hoisting/client.gen.go b/internal/test/anonymous_inner_hoisting/client.gen.go new file mode 100644 index 0000000000..74fe6907c2 --- /dev/null +++ b/internal/test/anonymous_inner_hoisting/client.gen.go @@ -0,0 +1,1320 @@ +// Package anonymous_inner_hoisting provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. +package anonymous_inner_hoisting + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/oapi-codegen/runtime" +) + +// Defines values for CatKind. +const ( + CatKindCat CatKind = "cat" +) + +// Valid indicates whether the value is a known member of the CatKind enum. +func (e CatKind) Valid() bool { + switch e { + case CatKindCat: + return true + default: + return false + } +} + +// Defines values for DogKind. +const ( + DogKindDog DogKind = "dog" +) + +// Valid indicates whether the value is a known member of the DogKind enum. +func (e DogKind) Valid() bool { + switch e { + case DogKindDog: + return true + default: + return false + } +} + +// Cat defines model for Cat. +type Cat struct { + Kind CatKind `json:"kind"` + Name *string `json:"name,omitempty"` +} + +// CatKind defines model for Cat.Kind. +type CatKind string + +// Dog defines model for Dog. +type Dog struct { + Kind DogKind `json:"kind"` + Name *string `json:"name,omitempty"` +} + +// DogKind defines model for Dog.Kind. +type DogKind string + +// PostBodyPropertyOneOfJSONBody defines parameters for PostBodyPropertyOneOf. +type PostBodyPropertyOneOfJSONBody struct { + Pet *PostBodyPropertyOneOfJSONBody_Pet `json:"pet,omitempty"` +} + +// PostBodyPropertyOneOfJSONBody_Pet defines parameters for PostBodyPropertyOneOf. +type PostBodyPropertyOneOfJSONBody_Pet struct { + union json.RawMessage +} + +// PostBodyRootOneOfJSONBody defines parameters for PostBodyRootOneOf. +type PostBodyRootOneOfJSONBody struct { + union json.RawMessage +} + +// GetResponseDeepNested200JSONResponseBody_Wrapper_Inner defines parameters for GetResponseDeepNested. +type GetResponseDeepNested200JSONResponseBody_Wrapper_Inner struct { + union json.RawMessage +} + +// GetResponseItemsOneOf200JSONResponseBody_Items_Item defines parameters for GetResponseItemsOneOf. +type GetResponseItemsOneOf200JSONResponseBody_Items_Item struct { + union json.RawMessage +} + +// GetResponseRootAnyOf200JSONResponseBody defines parameters for GetResponseRootAnyOf. +type GetResponseRootAnyOf200JSONResponseBody struct { + union json.RawMessage +} + +// GetResponseRootOneOf200JSONResponseBody defines parameters for GetResponseRootOneOf. +type GetResponseRootOneOf200JSONResponseBody struct { + union json.RawMessage +} + +// PostBodyPropertyOneOfJSONRequestBody defines body for PostBodyPropertyOneOf for application/json ContentType. +type PostBodyPropertyOneOfJSONRequestBody PostBodyPropertyOneOfJSONBody + +// PostBodyRootOneOfJSONRequestBody defines body for PostBodyRootOneOf for application/json ContentType. +type PostBodyRootOneOfJSONRequestBody PostBodyRootOneOfJSONBody + +// AsCat returns the union data inside the PostBodyPropertyOneOfJSONBody_Pet as a Cat +func (t PostBodyPropertyOneOfJSONBody_Pet) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the PostBodyPropertyOneOfJSONBody_Pet as the provided Cat +func (t *PostBodyPropertyOneOfJSONBody_Pet) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the PostBodyPropertyOneOfJSONBody_Pet, using the provided Cat +func (t *PostBodyPropertyOneOfJSONBody_Pet) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the PostBodyPropertyOneOfJSONBody_Pet as a Dog +func (t PostBodyPropertyOneOfJSONBody_Pet) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the PostBodyPropertyOneOfJSONBody_Pet as the provided Dog +func (t *PostBodyPropertyOneOfJSONBody_Pet) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the PostBodyPropertyOneOfJSONBody_Pet, using the provided Dog +func (t *PostBodyPropertyOneOfJSONBody_Pet) MergeDog(v Dog) 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 PostBodyPropertyOneOfJSONBody_Pet) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *PostBodyPropertyOneOfJSONBody_Pet) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsCat returns the union data inside the PostBodyRootOneOfJSONBody as a Cat +func (t PostBodyRootOneOfJSONBody) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the PostBodyRootOneOfJSONBody as the provided Cat +func (t *PostBodyRootOneOfJSONBody) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the PostBodyRootOneOfJSONBody, using the provided Cat +func (t *PostBodyRootOneOfJSONBody) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the PostBodyRootOneOfJSONBody as a Dog +func (t PostBodyRootOneOfJSONBody) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the PostBodyRootOneOfJSONBody as the provided Dog +func (t *PostBodyRootOneOfJSONBody) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the PostBodyRootOneOfJSONBody, using the provided Dog +func (t *PostBodyRootOneOfJSONBody) MergeDog(v Dog) 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 PostBodyRootOneOfJSONBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *PostBodyRootOneOfJSONBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsCat returns the union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as a Cat +func (t GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as the provided Cat +func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner, using the provided Cat +func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as a Dog +func (t GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as the provided Dog +func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner, using the provided Dog +func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) MergeDog(v Dog) 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 GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsCat returns the union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as a Cat +func (t GetResponseItemsOneOf200JSONResponseBody_Items_Item) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as the provided Cat +func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item, using the provided Cat +func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as a Dog +func (t GetResponseItemsOneOf200JSONResponseBody_Items_Item) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as the provided Dog +func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item, using the provided Dog +func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) MergeDog(v Dog) 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 GetResponseItemsOneOf200JSONResponseBody_Items_Item) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsCat returns the union data inside the GetResponseRootAnyOf200JSONResponseBody as a Cat +func (t GetResponseRootAnyOf200JSONResponseBody) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the GetResponseRootAnyOf200JSONResponseBody as the provided Cat +func (t *GetResponseRootAnyOf200JSONResponseBody) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the GetResponseRootAnyOf200JSONResponseBody, using the provided Cat +func (t *GetResponseRootAnyOf200JSONResponseBody) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the GetResponseRootAnyOf200JSONResponseBody as a Dog +func (t GetResponseRootAnyOf200JSONResponseBody) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the GetResponseRootAnyOf200JSONResponseBody as the provided Dog +func (t *GetResponseRootAnyOf200JSONResponseBody) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the GetResponseRootAnyOf200JSONResponseBody, using the provided Dog +func (t *GetResponseRootAnyOf200JSONResponseBody) MergeDog(v Dog) 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 GetResponseRootAnyOf200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *GetResponseRootAnyOf200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsCat returns the union data inside the GetResponseRootOneOf200JSONResponseBody as a Cat +func (t GetResponseRootOneOf200JSONResponseBody) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the GetResponseRootOneOf200JSONResponseBody as the provided Cat +func (t *GetResponseRootOneOf200JSONResponseBody) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the GetResponseRootOneOf200JSONResponseBody, using the provided Cat +func (t *GetResponseRootOneOf200JSONResponseBody) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the GetResponseRootOneOf200JSONResponseBody as a Dog +func (t GetResponseRootOneOf200JSONResponseBody) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the GetResponseRootOneOf200JSONResponseBody as the provided Dog +func (t *GetResponseRootOneOf200JSONResponseBody) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the GetResponseRootOneOf200JSONResponseBody, using the provided Dog +func (t *GetResponseRootOneOf200JSONResponseBody) MergeDog(v Dog) 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 GetResponseRootOneOf200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *GetResponseRootOneOf200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// Doer performs HTTP requests. +// +// The standard http.Client implements this interface. +type HttpRequestDoer interface { + Do(req *http.Request) (*http.Response, error) +} + +// Client which conforms to the OpenAPI3 specification for this service. +type Client struct { + // The endpoint of the server conforming to this interface, with scheme, + // https://api.deepmap.com for example. This can contain a path relative + // to the server, such as https://api.deepmap.com/dev-test, and all the + // paths in the swagger spec will be appended to the server. + Server string + + // Doer for performing requests, typically a *http.Client with any + // customized settings, such as certificate chains. + Client HttpRequestDoer + + // A list of callbacks for modifying requests which are generated before sending over + // the network. + RequestEditors []RequestEditorFn +} + +// ClientOption allows setting custom parameters during construction +type ClientOption func(*Client) error + +// Creates a new Client, with reasonable defaults +func NewClient(server string, opts ...ClientOption) (*Client, error) { + // create a client with sane default values + client := Client{ + Server: server, + } + // mutate client and add all optional params + for _, o := range opts { + if err := o(&client); err != nil { + return nil, err + } + } + // ensure the server URL always has a trailing slash + if !strings.HasSuffix(client.Server, "/") { + client.Server += "/" + } + // create httpClient, if not already present + if client.Client == nil { + client.Client = &http.Client{} + } + return &client, nil +} + +// WithHTTPClient allows overriding the default Doer, which is +// automatically created using http.Client. This is useful for tests. +func WithHTTPClient(doer HttpRequestDoer) ClientOption { + return func(c *Client) error { + c.Client = doer + return nil + } +} + +// WithRequestEditorFn allows setting up a callback function, which will be +// called right before sending the request. This can be used to mutate the request. +func WithRequestEditorFn(fn RequestEditorFn) ClientOption { + return func(c *Client) error { + c.RequestEditors = append(c.RequestEditors, fn) + return nil + } +} + +// The interface specification for the client above. +type ClientInterface interface { + // PostBodyPropertyOneOfWithBody request with any body + PostBodyPropertyOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostBodyPropertyOneOf(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostBodyRootOneOfWithBody request with any body + PostBodyRootOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostBodyRootOneOf(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetResponseDeepNested request + GetResponseDeepNested(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetResponseItemsOneOf request + GetResponseItemsOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetResponseRootAnyOf request + GetResponseRootAnyOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetResponseRootOneOf request + GetResponseRootOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) PostBodyPropertyOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostBodyPropertyOneOfRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PostBodyPropertyOneOf(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostBodyPropertyOneOfRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PostBodyRootOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostBodyRootOneOfRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) PostBodyRootOneOf(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostBodyRootOneOfRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetResponseDeepNested(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetResponseDeepNestedRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetResponseItemsOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetResponseItemsOneOfRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetResponseRootAnyOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetResponseRootAnyOfRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetResponseRootOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetResponseRootOneOfRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +// NewPostBodyPropertyOneOfRequest calls the generic PostBodyPropertyOneOf builder with application/json body +func NewPostBodyPropertyOneOfRequest(server string, body PostBodyPropertyOneOfJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostBodyPropertyOneOfRequestWithBody(server, "application/json", bodyReader) +} + +// NewPostBodyPropertyOneOfRequestWithBody generates requests for PostBodyPropertyOneOf with any type of body +func NewPostBodyPropertyOneOfRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/body-property-oneof") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodPost, queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewPostBodyRootOneOfRequest calls the generic PostBodyRootOneOf builder with application/json body +func NewPostBodyRootOneOfRequest(server string, body PostBodyRootOneOfJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostBodyRootOneOfRequestWithBody(server, "application/json", bodyReader) +} + +// NewPostBodyRootOneOfRequestWithBody generates requests for PostBodyRootOneOf with any type of body +func NewPostBodyRootOneOfRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/body-root-oneof") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodPost, queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetResponseDeepNestedRequest generates requests for GetResponseDeepNested +func NewGetResponseDeepNestedRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/response-deep-nested") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetResponseItemsOneOfRequest generates requests for GetResponseItemsOneOf +func NewGetResponseItemsOneOfRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/response-items-oneof") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetResponseRootAnyOfRequest generates requests for GetResponseRootAnyOf +func NewGetResponseRootAnyOfRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/response-root-anyof") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetResponseRootOneOfRequest generates requests for GetResponseRootOneOf +func NewGetResponseRootOneOfRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/response-root-oneof") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range c.RequestEditors { + if err := r(ctx, req); err != nil { + return err + } + } + for _, r := range additionalEditors { + if err := r(ctx, req); err != nil { + return err + } + } + return nil +} + +// ClientWithResponses builds on ClientInterface to offer response payloads +type ClientWithResponses struct { + ClientInterface +} + +// NewClientWithResponses creates a new ClientWithResponses, which wraps +// Client with return type handling +func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) { + client, err := NewClient(server, opts...) + if err != nil { + return nil, err + } + return &ClientWithResponses{client}, nil +} + +// WithBaseURL overrides the baseURL. +func WithBaseURL(baseURL string) ClientOption { + return func(c *Client) error { + newBaseURL, err := url.Parse(baseURL) + if err != nil { + return err + } + c.Server = newBaseURL.String() + return nil + } +} + +// ClientWithResponsesInterface is the interface specification for the client with responses above. +type ClientWithResponsesInterface interface { + // PostBodyPropertyOneOfWithBodyWithResponse request with any body + PostBodyPropertyOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error) + + PostBodyPropertyOneOfWithResponse(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error) + + // PostBodyRootOneOfWithBodyWithResponse request with any body + PostBodyRootOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error) + + PostBodyRootOneOfWithResponse(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error) + + // GetResponseDeepNestedWithResponse request + GetResponseDeepNestedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseDeepNestedResponse, error) + + // GetResponseItemsOneOfWithResponse request + GetResponseItemsOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseItemsOneOfResponse, error) + + // GetResponseRootAnyOfWithResponse request + GetResponseRootAnyOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootAnyOfResponse, error) + + // GetResponseRootOneOfWithResponse request + GetResponseRootOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootOneOfResponse, error) +} + +type PostBodyPropertyOneOfResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostBodyPropertyOneOfResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostBodyPropertyOneOfResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r PostBodyPropertyOneOfResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + +type PostBodyRootOneOfResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostBodyRootOneOfResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostBodyRootOneOfResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r PostBodyRootOneOfResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + +type GetResponseDeepNestedResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Wrapper *struct { + Inner *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner `json:"inner,omitempty"` + } `json:"wrapper,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r GetResponseDeepNestedResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetResponseDeepNestedResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r GetResponseDeepNestedResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + +type GetResponseItemsOneOfResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Items []GetResponseItemsOneOf200JSONResponseBody_Items_Item `json:"items"` + } +} + +// Status returns HTTPResponse.Status +func (r GetResponseItemsOneOfResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetResponseItemsOneOfResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r GetResponseItemsOneOfResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + +type GetResponseRootAnyOfResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *GetResponseRootAnyOf200JSONResponseBody +} + +// Status returns HTTPResponse.Status +func (r GetResponseRootAnyOfResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetResponseRootAnyOfResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r GetResponseRootAnyOfResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + +type GetResponseRootOneOfResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *GetResponseRootOneOf200JSONResponseBody +} + +// Status returns HTTPResponse.Status +func (r GetResponseRootOneOfResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetResponseRootOneOfResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers +func (r GetResponseRootOneOfResponse) ContentType() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Header.Get("Content-Type") + } + return "" +} + +// PostBodyPropertyOneOfWithBodyWithResponse request with arbitrary body returning *PostBodyPropertyOneOfResponse +func (c *ClientWithResponses) PostBodyPropertyOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error) { + rsp, err := c.PostBodyPropertyOneOfWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostBodyPropertyOneOfResponse(rsp) +} + +func (c *ClientWithResponses) PostBodyPropertyOneOfWithResponse(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error) { + rsp, err := c.PostBodyPropertyOneOf(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostBodyPropertyOneOfResponse(rsp) +} + +// PostBodyRootOneOfWithBodyWithResponse request with arbitrary body returning *PostBodyRootOneOfResponse +func (c *ClientWithResponses) PostBodyRootOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error) { + rsp, err := c.PostBodyRootOneOfWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostBodyRootOneOfResponse(rsp) +} + +func (c *ClientWithResponses) PostBodyRootOneOfWithResponse(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error) { + rsp, err := c.PostBodyRootOneOf(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostBodyRootOneOfResponse(rsp) +} + +// GetResponseDeepNestedWithResponse request returning *GetResponseDeepNestedResponse +func (c *ClientWithResponses) GetResponseDeepNestedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseDeepNestedResponse, error) { + rsp, err := c.GetResponseDeepNested(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetResponseDeepNestedResponse(rsp) +} + +// GetResponseItemsOneOfWithResponse request returning *GetResponseItemsOneOfResponse +func (c *ClientWithResponses) GetResponseItemsOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseItemsOneOfResponse, error) { + rsp, err := c.GetResponseItemsOneOf(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetResponseItemsOneOfResponse(rsp) +} + +// GetResponseRootAnyOfWithResponse request returning *GetResponseRootAnyOfResponse +func (c *ClientWithResponses) GetResponseRootAnyOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootAnyOfResponse, error) { + rsp, err := c.GetResponseRootAnyOf(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetResponseRootAnyOfResponse(rsp) +} + +// GetResponseRootOneOfWithResponse request returning *GetResponseRootOneOfResponse +func (c *ClientWithResponses) GetResponseRootOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootOneOfResponse, error) { + rsp, err := c.GetResponseRootOneOf(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetResponseRootOneOfResponse(rsp) +} + +// ParsePostBodyPropertyOneOfResponse parses an HTTP response from a PostBodyPropertyOneOfWithResponse call +func ParsePostBodyPropertyOneOfResponse(rsp *http.Response) (*PostBodyPropertyOneOfResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostBodyPropertyOneOfResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParsePostBodyRootOneOfResponse parses an HTTP response from a PostBodyRootOneOfWithResponse call +func ParsePostBodyRootOneOfResponse(rsp *http.Response) (*PostBodyRootOneOfResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostBodyRootOneOfResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetResponseDeepNestedResponse parses an HTTP response from a GetResponseDeepNestedWithResponse call +func ParseGetResponseDeepNestedResponse(rsp *http.Response) (*GetResponseDeepNestedResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetResponseDeepNestedResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Wrapper *struct { + Inner *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner `json:"inner,omitempty"` + } `json:"wrapper,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetResponseItemsOneOfResponse parses an HTTP response from a GetResponseItemsOneOfWithResponse call +func ParseGetResponseItemsOneOfResponse(rsp *http.Response) (*GetResponseItemsOneOfResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetResponseItemsOneOfResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Items []GetResponseItemsOneOf200JSONResponseBody_Items_Item `json:"items"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetResponseRootAnyOfResponse parses an HTTP response from a GetResponseRootAnyOfWithResponse call +func ParseGetResponseRootAnyOfResponse(rsp *http.Response) (*GetResponseRootAnyOfResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetResponseRootAnyOfResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest GetResponseRootAnyOf200JSONResponseBody + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetResponseRootOneOfResponse parses an HTTP response from a GetResponseRootOneOfWithResponse call +func ParseGetResponseRootOneOfResponse(rsp *http.Response) (*GetResponseRootOneOfResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetResponseRootOneOfResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest GetResponseRootOneOf200JSONResponseBody + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} diff --git a/internal/test/anonymous_inner_hoisting/client_test.go b/internal/test/anonymous_inner_hoisting/client_test.go new file mode 100644 index 0000000000..abdf532440 --- /dev/null +++ b/internal/test/anonymous_inner_hoisting/client_test.go @@ -0,0 +1,141 @@ +package anonymous_inner_hoisting + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func ptr[T any](v T) *T { return &v } + +func TestResponseRootOneOf_RoundTripCat(t *testing.T) { + cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")} + + var u GetResponseRootOneOf200JSONResponseBody + require.NoError(t, u.FromCat(cat)) + + b, err := json.Marshal(u) + require.NoError(t, err) + + var decoded GetResponseRootOneOf200JSONResponseBody + require.NoError(t, json.Unmarshal(b, &decoded)) + + got, err := decoded.AsCat() + require.NoError(t, err) + require.Equal(t, cat, got) +} + +func TestResponseRootAnyOf_RoundTripDog(t *testing.T) { + dog := Dog{Kind: DogKindDog, Name: ptr("rex")} + + var u GetResponseRootAnyOf200JSONResponseBody + require.NoError(t, u.FromDog(dog)) + + b, err := json.Marshal(u) + require.NoError(t, err) + + var decoded GetResponseRootAnyOf200JSONResponseBody + require.NoError(t, json.Unmarshal(b, &decoded)) + + got, err := decoded.AsDog() + require.NoError(t, err) + require.Equal(t, dog, got) +} + +func TestResponseItemsOneOf_RoundTripBothBranches(t *testing.T) { + cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")} + dog := Dog{Kind: DogKindDog, Name: ptr("rex")} + + var catItem GetResponseItemsOneOf200JSONResponseBody_Items_Item + require.NoError(t, catItem.FromCat(cat)) + var dogItem GetResponseItemsOneOf200JSONResponseBody_Items_Item + require.NoError(t, dogItem.FromDog(dog)) + + bCat, err := json.Marshal(catItem) + require.NoError(t, err) + bDog, err := json.Marshal(dogItem) + require.NoError(t, err) + + var decodedCat, decodedDog GetResponseItemsOneOf200JSONResponseBody_Items_Item + require.NoError(t, json.Unmarshal(bCat, &decodedCat)) + require.NoError(t, json.Unmarshal(bDog, &decodedDog)) + + gotCat, err := decodedCat.AsCat() + require.NoError(t, err) + require.Equal(t, cat, gotCat) + + gotDog, err := decodedDog.AsDog() + require.NoError(t, err) + require.Equal(t, dog, gotDog) +} + +func TestResponseDeepNested_RoundTrip(t *testing.T) { + cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")} + + var inner GetResponseDeepNested200JSONResponseBody_Wrapper_Inner + require.NoError(t, inner.FromCat(cat)) + + b, err := json.Marshal(inner) + require.NoError(t, err) + + var decoded GetResponseDeepNested200JSONResponseBody_Wrapper_Inner + require.NoError(t, json.Unmarshal(b, &decoded)) + + got, err := decoded.AsCat() + require.NoError(t, err) + require.Equal(t, cat, got) +} + +func TestBodyRootOneOf_RoundTripCat(t *testing.T) { + cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")} + + var body PostBodyRootOneOfJSONBody + require.NoError(t, body.FromCat(cat)) + + b, err := json.Marshal(body) + require.NoError(t, err) + + var decoded PostBodyRootOneOfJSONBody + require.NoError(t, json.Unmarshal(b, &decoded)) + + got, err := decoded.AsCat() + require.NoError(t, err) + require.Equal(t, cat, got) +} + +func TestBodyPropertyOneOf_RoundTripDog(t *testing.T) { + dog := Dog{Kind: DogKindDog, Name: ptr("rex")} + + var pet PostBodyPropertyOneOfJSONBody_Pet + require.NoError(t, pet.FromDog(dog)) + + b, err := json.Marshal(pet) + require.NoError(t, err) + + var decoded PostBodyPropertyOneOfJSONBody_Pet + require.NoError(t, json.Unmarshal(b, &decoded)) + + got, err := decoded.AsDog() + require.NoError(t, err) + require.Equal(t, dog, got) +} + +func TestMergeOverwritesPriorBranch(t *testing.T) { + cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")} + dog := Dog{Kind: DogKindDog, Name: ptr("rex")} + + var u GetResponseRootOneOf200JSONResponseBody + require.NoError(t, u.FromCat(cat)) + require.NoError(t, u.MergeDog(dog)) + + b, err := json.Marshal(u) + require.NoError(t, err) + + var decoded GetResponseRootOneOf200JSONResponseBody + require.NoError(t, json.Unmarshal(b, &decoded)) + + gotDog, err := decoded.AsDog() + require.NoError(t, err) + require.Equal(t, dog, gotDog) +} diff --git a/internal/test/anonymous_inner_hoisting/generate.go b/internal/test/anonymous_inner_hoisting/generate.go new file mode 100644 index 0000000000..19ff037202 --- /dev/null +++ b/internal/test/anonymous_inner_hoisting/generate.go @@ -0,0 +1,3 @@ +package anonymous_inner_hoisting + +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml spec.yaml diff --git a/internal/test/anonymous_inner_hoisting/spec.yaml b/internal/test/anonymous_inner_hoisting/spec.yaml new file mode 100644 index 0000000000..a6febff103 --- /dev/null +++ b/internal/test/anonymous_inner_hoisting/spec.yaml @@ -0,0 +1,132 @@ +openapi: 3.0.3 +info: + version: 1.0.0 + title: Anonymous Inner Hoisting + description: | + Exercises inline oneOf / anyOf schemas at every operation root and at + nested positions. Each generated wrapper type should receive + As() / From() / Merge() accessor methods. +paths: + + /response-root-oneof: + get: + operationId: getResponseRootOneOf + responses: + '200': + description: inline oneOf as the response body root + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + + /response-root-anyof: + get: + operationId: getResponseRootAnyOf + responses: + '200': + description: inline anyOf as the response body root + content: + application/json: + schema: + anyOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + + /response-items-oneof: + get: + operationId: getResponseItemsOneOf + responses: + '200': + description: inline oneOf as items of an array property + content: + application/json: + schema: + type: object + required: + - items + properties: + items: + type: array + items: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + + /response-deep-nested: + get: + operationId: getResponseDeepNested + responses: + '200': + description: inline oneOf nested inside a property of a property + content: + application/json: + schema: + type: object + properties: + wrapper: + type: object + properties: + inner: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + + /body-root-oneof: + post: + operationId: postBodyRootOneOf + requestBody: + required: true + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + responses: + '200': + description: ok + + /body-property-oneof: + post: + operationId: postBodyPropertyOneOf + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + pet: + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + responses: + '200': + description: ok + +components: + schemas: + Cat: + type: object + required: + - kind + properties: + kind: + type: string + enum: + - cat + name: + type: string + Dog: + type: object + required: + - kind + properties: + kind: + type: string + enum: + - dog + name: + type: string diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index 3e9467cb7f..fff0ef0f89 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/labstack/echo/v4" + "github.com/oapi-codegen/runtime" ) const ( @@ -48,11 +49,99 @@ type Rat struct { // apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme type apiKeyAuthContextKey string -// GetPets200JSONResponse_Data_Item defines parameters for GetPets. -type GetPets200JSONResponse_Data_Item struct { +// GetPets200JSONResponseBody_Data_Item defines parameters for GetPets. +type GetPets200JSONResponseBody_Data_Item struct { union json.RawMessage } +// AsCat returns the union data inside the GetPets200JSONResponseBody_Data_Item as a Cat +func (t GetPets200JSONResponseBody_Data_Item) AsCat() (Cat, error) { + var body Cat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromCat overwrites any union data inside the GetPets200JSONResponseBody_Data_Item as the provided Cat +func (t *GetPets200JSONResponseBody_Data_Item) FromCat(v Cat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeCat performs a merge with any union data inside the GetPets200JSONResponseBody_Data_Item, using the provided Cat +func (t *GetPets200JSONResponseBody_Data_Item) MergeCat(v Cat) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsDog returns the union data inside the GetPets200JSONResponseBody_Data_Item as a Dog +func (t GetPets200JSONResponseBody_Data_Item) AsDog() (Dog, error) { + var body Dog + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromDog overwrites any union data inside the GetPets200JSONResponseBody_Data_Item as the provided Dog +func (t *GetPets200JSONResponseBody_Data_Item) FromDog(v Dog) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeDog performs a merge with any union data inside the GetPets200JSONResponseBody_Data_Item, using the provided Dog +func (t *GetPets200JSONResponseBody_Data_Item) MergeDog(v Dog) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsRat returns the union data inside the GetPets200JSONResponseBody_Data_Item as a Rat +func (t GetPets200JSONResponseBody_Data_Item) AsRat() (Rat, error) { + var body Rat + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromRat overwrites any union data inside the GetPets200JSONResponseBody_Data_Item as the provided Rat +func (t *GetPets200JSONResponseBody_Data_Item) FromRat(v Rat) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeRat performs a merge with any union data inside the GetPets200JSONResponseBody_Data_Item, using the provided Rat +func (t *GetPets200JSONResponseBody_Data_Item) MergeRat(v Rat) 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 GetPets200JSONResponseBody_Data_Item) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *GetPets200JSONResponseBody_Data_Item) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -220,12 +309,9 @@ type GetPetsResponse struct { Body []byte HTTPResponse *http.Response JSON200 *struct { - Data *[]GetPets_200_Data_Item `json:"data,omitempty"` + Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"` } } -type GetPets_200_Data_Item struct { - union json.RawMessage -} // Status returns HTTPResponse.Status func (r GetPetsResponse) Status() string { @@ -276,7 +362,7 @@ func ParseGetPetsResponse(rsp *http.Response) (*GetPetsResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: var dest struct { - Data *[]GetPets_200_Data_Item `json:"data,omitempty"` + Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"` } if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go index e8550c87b3..c80b28dc4d 100644 --- a/internal/test/components/components.gen.go +++ b/internal/test/components/components.gen.go @@ -587,87 +587,6 @@ type EnsureEverythingIsReferencedTextRequestBody = EnsureEverythingIsReferencedT // BodyWithAddPropsJSONRequestBody defines body for BodyWithAddProps for application/json ContentType. type BodyWithAddPropsJSONRequestBody BodyWithAddPropsJSONBody -// Getter for additional properties for BodyWithAddPropsJSONBody. Returns the specified -// element and whether it was found -func (a BodyWithAddPropsJSONBody) Get(fieldName string) (value interface{}, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for BodyWithAddPropsJSONBody -func (a *BodyWithAddPropsJSONBody) Set(fieldName string, value interface{}) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]interface{}) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties -func (a *BodyWithAddPropsJSONBody) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["inner"]; found { - err = json.Unmarshal(raw, &a.Inner) - if err != nil { - return fmt.Errorf("error reading 'inner': %w", err) - } - delete(object, "inner") - } - - if raw, found := object["name"]; found { - err = json.Unmarshal(raw, &a.Name) - if err != nil { - return fmt.Errorf("error reading 'name': %w", err) - } - delete(object, "name") - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]interface{}) - for fieldName, fieldBuf := range object { - var fieldVal interface{} - err := json.Unmarshal(fieldBuf, &fieldVal) - if err != nil { - return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) - } - a.AdditionalProperties[fieldName] = fieldVal - } - } - return nil -} - -// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties -func (a BodyWithAddPropsJSONBody) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Inner != nil { - object["inner"], err = json.Marshal(a.Inner) - if err != nil { - return nil, fmt.Errorf("error marshaling 'inner': %w", err) - } - } - - object["name"], err = json.Marshal(a.Name) - if err != nil { - return nil, fmt.Errorf("error marshaling 'name': %w", err) - } - - for fieldName, field := range a.AdditionalProperties { - object[fieldName], err = json.Marshal(field) - if err != nil { - return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) - } - } - return json.Marshal(object) -} - // Getter for additional properties for AdditionalPropertiesObject1. Returns the specified // element and whether it was found func (a AdditionalPropertiesObject1) Get(fieldName string) (value int, found bool) { @@ -990,6 +909,87 @@ func (a *OneOfObject13) Set(fieldName string, value interface{}) { a.AdditionalProperties[fieldName] = value } +// Getter for additional properties for BodyWithAddPropsJSONBody. Returns the specified +// element and whether it was found +func (a BodyWithAddPropsJSONBody) Get(fieldName string) (value interface{}, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for BodyWithAddPropsJSONBody +func (a *BodyWithAddPropsJSONBody) Set(fieldName string, value interface{}) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]interface{}) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties +func (a *BodyWithAddPropsJSONBody) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["inner"]; found { + err = json.Unmarshal(raw, &a.Inner) + if err != nil { + return fmt.Errorf("error reading 'inner': %w", err) + } + delete(object, "inner") + } + + if raw, found := object["name"]; found { + err = json.Unmarshal(raw, &a.Name) + if err != nil { + return fmt.Errorf("error reading 'name': %w", err) + } + delete(object, "name") + } + + if len(object) != 0 { + a.AdditionalProperties = make(map[string]interface{}) + for fieldName, fieldBuf := range object { + var fieldVal interface{} + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties +func (a BodyWithAddPropsJSONBody) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + if a.Inner != nil { + object["inner"], err = json.Marshal(a.Inner) + if err != nil { + return nil, fmt.Errorf("error marshaling 'inner': %w", err) + } + } + + object["name"], err = json.Marshal(a.Name) + if err != nil { + return nil, fmt.Errorf("error marshaling 'name': %w", err) + } + + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} + // AsOneOfVariant4 returns the union data inside the AnyOfObject1 as a OneOfVariant4 func (t AnyOfObject1) AsOneOfVariant4() (OneOfVariant4, error) { var body OneOfVariant4 diff --git a/internal/test/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go index fee7e80abb..4e13565987 100644 --- a/internal/test/issues/issue-1277/content-array.gen.go +++ b/internal/test/issues/issue-1277/content-array.gen.go @@ -16,32 +16,32 @@ import ( "github.com/go-chi/chi/v5" ) -// Test200JSONResponse_Item defines parameters for Test. -type Test200JSONResponse_Item struct { +// Test200JSONResponseBody_Item defines parameters for Test. +type Test200JSONResponseBody_Item struct { Field1 *string `json:"field1,omitempty"` Field2 *string `json:"field2,omitempty"` AdditionalProperties map[string]interface{} `json:"-"` } -// Getter for additional properties for Test200JSONResponse_Item. Returns the specified +// Getter for additional properties for Test200JSONResponseBody_Item. Returns the specified // element and whether it was found -func (a Test200JSONResponse_Item) Get(fieldName string) (value interface{}, found bool) { +func (a Test200JSONResponseBody_Item) Get(fieldName string) (value interface{}, found bool) { if a.AdditionalProperties != nil { value, found = a.AdditionalProperties[fieldName] } return } -// Setter for additional properties for Test200JSONResponse_Item -func (a *Test200JSONResponse_Item) Set(fieldName string, value interface{}) { +// Setter for additional properties for Test200JSONResponseBody_Item +func (a *Test200JSONResponseBody_Item) Set(fieldName string, value interface{}) { if a.AdditionalProperties == nil { a.AdditionalProperties = make(map[string]interface{}) } a.AdditionalProperties[fieldName] = value } -// Override default JSON handling for Test200JSONResponse_Item to handle AdditionalProperties -func (a *Test200JSONResponse_Item) UnmarshalJSON(b []byte) error { +// Override default JSON handling for Test200JSONResponseBody_Item to handle AdditionalProperties +func (a *Test200JSONResponseBody_Item) UnmarshalJSON(b []byte) error { object := make(map[string]json.RawMessage) err := json.Unmarshal(b, &object) if err != nil { @@ -78,8 +78,8 @@ func (a *Test200JSONResponse_Item) UnmarshalJSON(b []byte) error { return nil } -// Override default JSON handling for Test200JSONResponse_Item to handle AdditionalProperties -func (a Test200JSONResponse_Item) MarshalJSON() ([]byte, error) { +// Override default JSON handling for Test200JSONResponseBody_Item to handle AdditionalProperties +func (a Test200JSONResponseBody_Item) MarshalJSON() ([]byte, error) { var err error object := make(map[string]json.RawMessage) @@ -272,12 +272,7 @@ type ClientWithResponsesInterface interface { type TestResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *[]Test_200_Item -} -type Test_200_Item struct { - Field1 *string `json:"field1,omitempty"` - Field2 *string `json:"field2,omitempty"` - AdditionalProperties map[string]interface{} `json:"-"` + JSON200 *[]Test200JSONResponseBody_Item } // Status returns HTTPResponse.Status @@ -328,7 +323,7 @@ func ParseTestResponse(rsp *http.Response) (*TestResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest []Test_200_Item + var dest []Test200JSONResponseBody_Item if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -505,7 +500,7 @@ type TestResponseObject interface { VisitTestResponse(w http.ResponseWriter) error } -type Test200JSONResponse []Test200JSONResponse_Item +type Test200JSONResponse []Test200JSONResponseBody_Item func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error { diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go index f708015ae6..c9c57df5fb 100644 --- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go +++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go @@ -29,6 +29,47 @@ type Bionicle struct { // BionicleName defines model for bionicleName. type BionicleName = string +// GetBionicleName400JSONResponseBody defines parameters for GetBionicleName. +type GetBionicleName400JSONResponseBody struct { + union json.RawMessage +} + +// AsBionicle returns the union data inside the GetBionicleName400JSONResponseBody as a Bionicle +func (t GetBionicleName400JSONResponseBody) AsBionicle() (Bionicle, error) { + var body Bionicle + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromBionicle overwrites any union data inside the GetBionicleName400JSONResponseBody as the provided Bionicle +func (t *GetBionicleName400JSONResponseBody) FromBionicle(v Bionicle) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeBionicle performs a merge with any union data inside the GetBionicleName400JSONResponseBody, using the provided Bionicle +func (t *GetBionicleName400JSONResponseBody) MergeBionicle(v Bionicle) 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 GetBionicleName400JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *GetBionicleName400JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // ServerInterface represents all server handlers. type ServerInterface interface { @@ -211,9 +252,7 @@ func (response GetBionicleName200JSONResponse) VisitGetBionicleNameResponse(w ht return err } -type GetBionicleName400JSONResponse struct { - union json.RawMessage -} +type GetBionicleName400JSONResponse = GetBionicleName400JSONResponseBody func (response GetBionicleName400JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error { diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go index 9c856f981b..b11772fd3c 100644 --- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go +++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go @@ -204,14 +204,20 @@ func (response GetBionicleName200JSONResponse) VisitGetBionicleNameResponse(w ht return err } -type GetBionicleName400JSONResponse struct { - union json.RawMessage +type GetBionicleName400JSONResponse externalRef0.GetBionicleName400JSONResponseBody + +func (t GetBionicleName400JSONResponse) MarshalJSON() ([]byte, error) { + return externalRef0.GetBionicleName400JSONResponseBody(t).MarshalJSON() +} + +func (t *GetBionicleName400JSONResponse) UnmarshalJSON(b []byte) error { + return (*externalRef0.GetBionicleName400JSONResponseBody)(t).UnmarshalJSON(b) } func (response GetBionicleName400JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.union); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") diff --git a/internal/test/issues/issue-1378/fooservice/fooservice_test.go b/internal/test/issues/issue-1378/fooservice/fooservice_test.go new file mode 100644 index 0000000000..0d3319ea6b --- /dev/null +++ b/internal/test/issues/issue-1378/fooservice/fooservice_test.go @@ -0,0 +1,27 @@ +package fooservice + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + bionicle "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/bionicle" +) + +// TestExternalRefUnionResponseSerialization locks in the fix for the +// case where a strict-server response envelope wraps an external union +// type. Because the strict envelope is a defined type (`type X +// externalRef0.Y`), methods on Y don't transfer; without an explicit +// MarshalJSON delegator the encode falls back to struct-field +// serialization on the unexported `union` field and produces `{}`. +func TestExternalRefUnionResponseSerialization(t *testing.T) { + var body bionicle.GetBionicleName400JSONResponseBody + require.NoError(t, body.FromBionicle(bionicle.Bionicle{Name: "tahu"})) + + resp := GetBionicleName400JSONResponse(body) + + got, err := json.Marshal(resp) + require.NoError(t, err) + require.JSONEq(t, `{"name":"tahu"}`, string(got)) +} diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go index 348bcff460..b97ae67fa3 100644 --- a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -258,17 +258,17 @@ type QueryJSONBody struct { Q *string `json:"q,omitempty"` } -// PatchResource200ApplicationJSONPatchPlusJSONResponse1 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchPlusJSONResponse1 = []Resource +// PatchResource200ApplicationJSONPatchPlusJSONResponseBody1 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchPlusJSONResponseBody1 = []Resource -// PatchResource200ApplicationJSONPatchPlusJSONResponse2 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchPlusJSONResponse2 = string +// PatchResource200ApplicationJSONPatchPlusJSONResponseBody2 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchPlusJSONResponseBody2 = string -// PatchResource200ApplicationJSONPatchQueryPlusJSONResponse1 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchQueryPlusJSONResponse1 = []Resource +// PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody1 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody1 = []Resource -// PatchResource200ApplicationJSONPatchQueryPlusJSONResponse2 defines parameters for PatchResource. -type PatchResource200ApplicationJSONPatchQueryPlusJSONResponse2 = string +// PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody2 defines parameters for PatchResource. +type PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody2 = string // PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. type PostFooJSONRequestBody PostFooJSONBody @@ -2308,10 +2308,6 @@ type PatchResourceResponse struct { ApplicationjsonPatchQueryJSON200 *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON ApplicationmergePatchJSON200 *N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON } -type PatchResource200ApplicationJSONPatchPlusJSON1 = []Resource -type PatchResource200ApplicationJSONPatchPlusJSON2 = string -type PatchResource200ApplicationJSONPatchQueryPlusJSON1 = []Resource -type PatchResource200ApplicationJSONPatchQueryPlusJSON2 = string // Status returns HTTPResponse.Status func (r PatchResourceResponse) Status() string { diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go index caf622b4b2..24563e498f 100644 --- a/internal/test/strict-server/chi/server.gen.go +++ b/internal/test/strict-server/chi/server.gen.go @@ -1184,9 +1184,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/chi/types.gen.go b/internal/test/strict-server/chi/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/chi/types.gen.go +++ b/internal/test/strict-server/chi/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index 5efe7502b1..d4cdfbc074 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -39,8 +39,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -84,6 +89,68 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -1572,11 +1639,8 @@ type UnionExampleResponse struct { Body []byte HTTPResponse *http.Response ApplicationalternativeJSON200 *Example - JSON200 *struct { - union json.RawMessage - } + JSON200 *UnionExample200JSONResponseBody } -type UnionExample2000 = string // Status returns HTTPResponse.Status func (r UnionExampleResponse) Status() string { @@ -2099,9 +2163,7 @@ func ParseUnionExampleResponse(rsp *http.Response) (*UnionExampleResponse, error response.ApplicationalternativeJSON200 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200: - var dest struct { - union json.RawMessage - } + var dest UnionExample200JSONResponseBody if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go index 3a314fb909..041e8f75d1 100644 --- a/internal/test/strict-server/echo/server.gen.go +++ b/internal/test/strict-server/echo/server.gen.go @@ -904,9 +904,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/echo/types.gen.go b/internal/test/strict-server/echo/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/echo/types.gen.go +++ b/internal/test/strict-server/echo/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go index bdb00bfcdb..caea58b285 100644 --- a/internal/test/strict-server/fiber/server.gen.go +++ b/internal/test/strict-server/fiber/server.gen.go @@ -8,7 +8,6 @@ import ( "compress/gzip" "context" "encoding/base64" - "encoding/json" "errors" "fmt" "io" @@ -1010,9 +1009,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/fiber/types.gen.go +++ b/internal/test/strict-server/fiber/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go index 00ea144ab2..0642639e37 100644 --- a/internal/test/strict-server/gin/server.gen.go +++ b/internal/test/strict-server/gin/server.gen.go @@ -979,9 +979,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/gin/types.gen.go b/internal/test/strict-server/gin/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/gin/types.gen.go +++ b/internal/test/strict-server/gin/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go index 2c28c12eb4..85fc6fe3a9 100644 --- a/internal/test/strict-server/gorilla/server.gen.go +++ b/internal/test/strict-server/gorilla/server.gen.go @@ -1095,9 +1095,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/gorilla/types.gen.go b/internal/test/strict-server/gorilla/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/gorilla/types.gen.go +++ b/internal/test/strict-server/gorilla/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go index 66d0dce0bb..6bef496890 100644 --- a/internal/test/strict-server/iris/server.gen.go +++ b/internal/test/strict-server/iris/server.gen.go @@ -8,7 +8,6 @@ import ( "compress/gzip" "context" "encoding/base64" - "encoding/json" "errors" "fmt" "io" @@ -844,9 +843,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/iris/types.gen.go b/internal/test/strict-server/iris/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/iris/types.gen.go +++ b/internal/test/strict-server/iris/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go index ac8d245c8d..adca621779 100644 --- a/internal/test/strict-server/stdhttp/server.gen.go +++ b/internal/test/strict-server/stdhttp/server.gen.go @@ -1090,9 +1090,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion } type UnionExample200JSONResponse struct { - Body struct { - union json.RawMessage - } + Body UnionExample200JSONResponseBody Headers UnionExample200ResponseHeaders } diff --git a/internal/test/strict-server/stdhttp/types.gen.go b/internal/test/strict-server/stdhttp/types.gen.go index 532c5ebae3..08ae8548e1 100644 --- a/internal/test/strict-server/stdhttp/types.gen.go +++ b/internal/test/strict-server/stdhttp/types.gen.go @@ -3,6 +3,12 @@ // Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT. package api +import ( + "encoding/json" + + "github.com/oapi-codegen/runtime" +) + // Example defines model for example. type Example struct { Value *string `json:"value,omitempty"` @@ -26,8 +32,13 @@ type HeadersExampleParams struct { Header2 *int `json:"header2,omitempty"` } -// UnionExample200JSONResponse0 defines parameters for UnionExample. -type UnionExample200JSONResponse0 = string +// UnionExample200JSONResponseBody0 defines parameters for UnionExample. +type UnionExample200JSONResponseBody0 = string + +// UnionExample200JSONResponseBody defines parameters for UnionExample. +type UnionExample200JSONResponseBody struct { + union json.RawMessage +} // JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType. type JSONExampleJSONRequestBody = Example @@ -70,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example // UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType. type UnionExampleJSONRequestBody = Example + +// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0 +func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) { + var body UnionExample200JSONResponseBody0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0 +func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example +func (t UnionExample200JSONResponseBody) AsExample() (Example, error) { + var body Example + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example +func (t *UnionExample200JSONResponseBody) FromExample(v Example) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example +func (t *UnionExample200JSONResponseBody) MergeExample(v Example) 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 UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 8514ef83e1..fb588dcfa5 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -345,7 +345,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { if opts.Generate.Strict { var responses []ResponseDefinition if spec.Components != nil { - responses, err = GenerateResponseDefinitions("", spec.Components.Responses) + responses, err = GenerateResponseDefinitions("", spec.Components.Responses, "") if err != nil { return "", fmt.Errorf("error generation response definitions for schema: %w", err) } @@ -580,13 +580,28 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op allTypes = append(allTypes, securitySchemeTypes...) } - // Go through all operations, and add their types to allTypes, so that we can - // scan all of them for enums. Operation definitions are handled differently - // from the rest, so let's keep track of enumTypes separately, which will contain - // all types needed to be scanned for enums, which includes those within operations. - enumTypes := allTypes + // allTypes stays components-only — it's the slice passed to + // GenerateTypes (typedef.tmpl) for top-level type declarations. + // Op-derived types are declared by their per-context templates + // (param-types.tmpl, request-bodies.tmpl, client-with-responses.tmpl). + // + // boilerplateTypes is the wider universe for the method-emitting + // passes (enum scanning, additionalProperties marshalers, union + // accessors). Inline union/additionalProperties types living + // inside operations (params, request bodies, response schemas + // and any nested AdditionalTypeDefinitions) historically never + // reached these passes, so accessor methods were silently + // missing. Folding them in here is what fixes that. + boilerplateTypes := slices.Clone(allTypes) for _, op := range ops { - enumTypes = append(enumTypes, op.TypeDefinitions...) + boilerplateTypes = append(boilerplateTypes, op.TypeDefinitions...) + respDefs, err := op.GetResponseTypeDefinitions() + if err != nil { + return "", fmt.Errorf("error collecting response type definitions for %s: %w", op.OperationId, err) + } + for _, rd := range respDefs { + boilerplateTypes = append(boilerplateTypes, rd.AdditionalTypeDefinitions...) + } } operationsOut, err := GenerateTypesForOperations(t, ops) @@ -594,7 +609,7 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op return "", fmt.Errorf("error generating Go types for component request bodies: %w", err) } - enumsOut, err := GenerateEnums(t, enumTypes) + enumsOut, err := GenerateEnums(t, boilerplateTypes) if err != nil { return "", fmt.Errorf("error generating code for type enums: %w", err) } @@ -604,17 +619,17 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op return "", fmt.Errorf("error generating code for type definitions: %w", err) } - allOfBoilerplate, err := GenerateAdditionalPropertyBoilerplate(t, allTypes) + allOfBoilerplate, err := GenerateAdditionalPropertyBoilerplate(t, boilerplateTypes) if err != nil { return "", fmt.Errorf("error generating allOf boilerplate: %w", err) } - unionBoilerplate, err := GenerateUnionBoilerplate(t, allTypes) + unionBoilerplate, err := GenerateUnionBoilerplate(t, boilerplateTypes) if err != nil { return "", fmt.Errorf("error generating union boilerplate: %w", err) } - unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, allTypes) + unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, boilerplateTypes) if err != nil { return "", fmt.Errorf("error generating boilerplate for union types with additionalProperties: %w", err) } @@ -1120,7 +1135,12 @@ func GenerateAdditionalPropertyBoilerplate(t *template.Template, typeDefs []Type func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) { var filteredTypes []TypeDefinition + seen := map[string]bool{} for _, t := range typeDefs { + if seen[t.TypeName] { + continue + } + seen[t.TypeName] = true if len(t.Schema.UnionElements) != 0 { filteredTypes = append(filteredTypes, t) } @@ -1141,7 +1161,12 @@ func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) ( func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) { var filteredTypes []TypeDefinition + seen := map[string]bool{} for _, t := range typeDefs { + if seen[t.TypeName] { + continue + } + seen[t.TypeName] = true if len(t.Schema.UnionElements) != 0 && t.Schema.HasAdditionalProperties { filteredTypes = append(filteredTypes, t) } diff --git a/pkg/codegen/externalref.go b/pkg/codegen/externalref.go index a48b3d4e1e..829885a5b3 100644 --- a/pkg/codegen/externalref.go +++ b/pkg/codegen/externalref.go @@ -58,6 +58,20 @@ func ensureExternalRefsInParameterDefinitions(defs *[]ParameterDefinition, ref s } } +// externalPackageFor returns the imported Go package name for a `$ref` that +// targets a file outside the current spec. Returns an empty string when the +// ref is empty, points within the current spec, or has no import-mapping. +func externalPackageFor(ref string) string { + if ref == "" { + return "" + } + parts := strings.SplitN(ref, "#", 2) + if pack, ok := globalState.importMapping[parts[0]]; ok { + return pack.Name + } + return "" +} + // ensureExternalRefsInSchema ensures that when an externalRef (`$ref` that points to a file that isn't the current spec) is encountered, we make sure we update our underlying `RefType` to make sure that we point to that type. // // This only happens if we have a non-empty `ref` passed in, and that `ref` isn't pointing to something in our file @@ -68,13 +82,26 @@ func ensureExternalRefsInSchema(schema *Schema, ref string) { return } - // if this is already defined as the start of a struct, we shouldn't inject **??** - if strings.HasPrefix(schema.GoType, "struct {") { + parts := strings.SplitN(ref, "#", 2) + pack, ok := globalState.importMapping[parts[0]] + if !ok { return } - parts := strings.SplitN(ref, "#", 2) - if pack, ok := globalState.importMapping[parts[0]]; ok { + // if this is already defined as the start of a struct, we shouldn't inject **??** + if !strings.HasPrefix(schema.GoType, "struct {") { schema.RefType = fmt.Sprintf("%s.%s", pack.Name, schema.GoType) } + + // Qualify union branch types. Each UnionElement was resolved as a + // local reference during generateUnion (e.g. "Bionicle"); when the + // enclosing schema came from an externally-ref'd file the branches + // actually live in the imported package, so the As/From/Merge + // methods generated by union.tmpl must use ".Bionicle" instead. + for i, elem := range schema.UnionElements { + s := string(elem) + if !strings.Contains(s, ".") { + schema.UnionElements[i] = UnionElement(fmt.Sprintf("%s.%s", pack.Name, s)) + } + } } diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index 0fedc32be2..4087d30fec 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -329,6 +329,7 @@ type OperationDefinition struct { Spec *openapi3.Operation IsAlias bool // True when this path is a $ref alias of another path item AliasTarget string // When IsAlias is true, this is the OperationId of the canonical operation (for route registration to reference the correct wrapper) + PathItemRef string // The path item's $ref (if any); used to qualify externally-loaded schemas referenced from this operation's responses } // HandlerName returns the OperationId to use when referencing the server-side @@ -401,10 +402,10 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini // We can only generate a type if we have a value: if responseRef.Value != nil { - jsonCount := 0 + supportedCount := 0 for mediaType := range responseRef.Value.Content { - if util.IsMediaTypeJson(mediaType) { - jsonCount++ + if isMediaTypeSupported(mediaType) { + supportedCount++ } } @@ -413,57 +414,64 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini contentType := responseRef.Value.Content[contentTypeName] // We can only generate a type if we have a schema: if contentType.Schema != nil { - // When a response has multiple JSON content types (e.g., - // application/json, application/json-patch+json, and - // application/merge-patch+json), we include a content-type-derived - // segment in the schema path. This is necessary because - // GenerateGoSchema uses the path to name any inline types it - // creates (e.g., oneOf union members). Without the content type - // in the path, all content types for the same response produce - // identically-named inline types. If those content types have - // different schemas, the result is conflicting type declarations; - // if they have the same schema, the result is duplicate - // declarations. Both cases produce code that won't compile. - // - // We only add the content type segment when collision resolution - // is enabled (resolve-type-name-collisions) and jsonCount > 1, - // to avoid changing type names for existing users. Ideally the - // media type would always be part of the path for consistency. - // TODO: revisit this at the next major version change — - // always include the media type in the schema path. - schemaPath := []string{o.OperationId, responseName} - if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) && globalState.options.OutputOptions.ResolveTypeNameCollisions { - schemaPath = append(schemaPath, mediaTypeToCamelCase(contentTypeName)) - } - responseSchema, err := GenerateGoSchema(contentType.Schema, schemaPath) - if err != nil { - return nil, fmt.Errorf("unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) - } - - var typeName string + var typeName, tag string switch { // HAL+JSON: case slices.Contains(contentTypesHalJSON, contentTypeName): typeName = fmt.Sprintf("HALJSON%s", nameNormalizer(responseName)) + tag = "HALJSON" case contentTypeName == "application/json": // if it's the standard application/json typeName = fmt.Sprintf("JSON%s", nameNormalizer(responseName)) + tag = "JSON" // Vendored JSON case slices.Contains(contentTypesJSON, contentTypeName) || util.IsMediaTypeJson(contentTypeName): baseTypeName := fmt.Sprintf("%s%s", nameNormalizer(contentTypeName), nameNormalizer(responseName)) typeName = strings.ReplaceAll(baseTypeName, "Json", "JSON") + tag = strings.ReplaceAll(nameNormalizer(contentTypeName), "Json", "JSON") // YAML: case slices.Contains(contentTypesYAML, contentTypeName): typeName = fmt.Sprintf("YAML%s", nameNormalizer(responseName)) + tag = "YAML" // XML: case slices.Contains(contentTypesXML, contentTypeName): typeName = fmt.Sprintf("XML%s", nameNormalizer(responseName)) + tag = "XML" default: continue } + // Use the same body-type name as the server-side + // GenerateResponseDefinitions ("Body" suffixed so it + // doesn't collide with the strict envelope's struct + // wrapper) as the schema-path root. The canonical + // declaration happens server-side; here we just point + // RefType at the same name so the JSON field + // renders as a pointer to it. + responseBodyTypeName := o.OperationId + responseName + tag + "ResponseBody" + schemaPath := []string{responseBodyTypeName} + responseSchema, err := GenerateGoSchema(contentType.Schema, schemaPath) + if err != nil { + return nil, fmt.Errorf("unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err) + } + + // Hoist inline response-root schemas that need + // method-emitting boilerplate (UnionElements / + // AdditionalProperties). For external path items, + // qualify with the imported package — see the + // equivalent block in GenerateResponseDefinitions for + // rationale. + if !IsGoTypeReference(responseRef.Ref) && responseSchema.RefType == "" && + (len(responseSchema.UnionElements) != 0 || responseSchema.HasAdditionalProperties) { + if externalPkg := externalPackageFor(o.PathItemRef); externalPkg != "" { + responseSchema.RefType = fmt.Sprintf("%s.%s", externalPkg, responseBodyTypeName) + } else { + responseSchema.RefType = responseBodyTypeName + } + } + td := ResponseTypeDefinition{ TypeDefinition: TypeDefinition{ TypeName: typeName, @@ -478,7 +486,7 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini if err != nil { return nil, fmt.Errorf("error dereferencing response Ref: %w", err) } - if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) { + if supportedCount > 1 { if resolved := resolvedNameForRefPath(responseRef.Ref, contentTypeName); resolved != "" { refType = resolved + mediaTypeToCamelCase(contentTypeName) } else { @@ -808,14 +816,14 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { return nil, err } - bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(operationId, op.RequestBody) + bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(operationId, op.RequestBody, pathItem.Ref) if err != nil { return nil, fmt.Errorf("error generating body definitions: %w", err) } ensureExternalRefsInRequestBodyDefinitions(&bodyDefinitions, pathItem.Ref) - responseDefinitions, err := GenerateResponseDefinitions(operationId, op.Responses.Map()) + responseDefinitions, err := GenerateResponseDefinitions(operationId, op.Responses.Map(), pathItem.Ref) if err != nil { return nil, fmt.Errorf("error generating response definitions: %w", err) } @@ -838,6 +846,7 @@ func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) { TypeDefinitions: typeDefinitions, IsAlias: isAlias, AliasTarget: aliasTarget, + PathItemRef: pathItem.Ref, } // check for overrides of SecurityDefinitions. @@ -887,7 +896,14 @@ func generateDefaultOperationID(opName string, requestPath string) (string, erro // GenerateBodyDefinitions turns the Swagger body definitions into a list of our body // definitions which will be used for code generation. -func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBodyRef) ([]RequestBodyDefinition, []TypeDefinition, error) { +// +// pathItemRef is the path item's $ref (if any). When non-empty and pointing at +// an external file, the body type that would otherwise be hoisted locally is +// replaced by a reference to the imported package's same-named type — the +// imported package already declares it (with any As/From/Merge methods), so +// redeclaring locally would just produce an awkward duplicate with +// package-qualified union elements. +func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBodyRef, pathItemRef string) ([]RequestBodyDefinition, []TypeDefinition, error) { if bodyOrRef == nil { return nil, nil, nil } @@ -942,24 +958,31 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody // type under #/components, we'll define a type for it, so // that we have an easy to use type for marshaling. if bodySchema.RefType == "" { - if contentType == "application/x-www-form-urlencoded" { - // Apply the appropriate structure tag if the request - // schema was defined under the operations' section. - for i := range bodySchema.Properties { - bodySchema.Properties[i].NeedsFormTag = true - } + if externalPkg := externalPackageFor(pathItemRef); externalPkg != "" { + // The operation's path item came from an external file; the + // imported package already declares this body type with the + // matching name. Reference it instead of redeclaring. + bodySchema.RefType = fmt.Sprintf("%s.%s", externalPkg, bodyTypeName) + } else { + if contentType == "application/x-www-form-urlencoded" { + // Apply the appropriate structure tag if the request + // schema was defined under the operations' section. + for i := range bodySchema.Properties { + bodySchema.Properties[i].NeedsFormTag = true + } - // Regenerate the Golang struct adding the new form tag. - bodySchema.GoType = GenStructFromSchema(bodySchema) - } + // Regenerate the Golang struct adding the new form tag. + bodySchema.GoType = GenStructFromSchema(bodySchema) + } - td := TypeDefinition{ - TypeName: bodyTypeName, - Schema: bodySchema, + td := TypeDefinition{ + TypeName: bodyTypeName, + Schema: bodySchema, + } + typeDefinitions = append(typeDefinitions, td) + // The body schema now is a reference to a type + bodySchema.RefType = bodyTypeName } - typeDefinitions = append(typeDefinitions, td) - // The body schema now is a reference to a type - bodySchema.RefType = bodyTypeName } bd := RequestBodyDefinition{ @@ -986,7 +1009,9 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody return bodyDefinitions, typeDefinitions, nil } -func GenerateResponseDefinitions(operationID string, responses map[string]*openapi3.ResponseRef) ([]ResponseDefinition, error) { +func GenerateResponseDefinitions(operationID string, responses map[string]*openapi3.ResponseRef, pathItemRef string) ([]ResponseDefinition, error) { + externalPkg := externalPackageFor(pathItemRef) + var responseDefinitions []ResponseDefinition // do not let multiple status codes ref to same response, it will break the type switch refSet := make(map[string]struct{}) @@ -1023,11 +1048,44 @@ func GenerateResponseDefinitions(operationID string, responses map[string]*opena } responseTypeName := operationID + statusCode + tag + "Response" - contentSchema, err := GenerateGoSchema(content.Schema, []string{responseTypeName}) + // The strict-server envelope keeps the bare ...Response name + // (e.g. "GetPing200JSONResponse"); the hoisted body type is + // suffixed so the envelope can reference it without colliding + // (the strict envelope is sometimes a struct that wraps the + // body in a Body field, which would self-reference if the + // names matched). + responseBodyTypeName := responseTypeName + "Body" + contentSchema, err := GenerateGoSchema(content.Schema, []string{responseBodyTypeName}) if err != nil { return nil, fmt.Errorf("error generating request body definition: %w", err) } + // Hoist inline response-root schemas that need method-emitting + // boilerplate (UnionElements / AdditionalProperties) to a + // synthetic top-level TypeDefinition. The hoisted typedef flows + // via op.TypeDefinitions (collected in + // GenerateTypeDefsForOperation) and gets declared once via + // typedef.tmpl with full union/additionalProperties methods. + // The strict-server template references it as the body type + // from the envelope. + // + // When the operation came from an externally-ref'd path item, + // the imported package generated the same hoisted name, so we + // reference it instead of redeclaring locally. + if !IsGoTypeReference(responseOrRef.Ref) && contentSchema.RefType == "" && + (len(contentSchema.UnionElements) != 0 || contentSchema.HasAdditionalProperties) { + if externalPkg != "" { + contentSchema.RefType = fmt.Sprintf("%s.%s", externalPkg, responseBodyTypeName) + } else { + contentSchema.AdditionalTypes = append(contentSchema.AdditionalTypes, TypeDefinition{ + TypeName: responseBodyTypeName, + JsonName: responseBodyTypeName, + Schema: contentSchema, + }) + contentSchema.RefType = responseBodyTypeName + } + } + rcd := ResponseContentDefinition{ ContentType: contentType, NameTag: tag, @@ -1157,7 +1215,6 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition { s.Properties = append(s.Properties, prop) } - s.Description = op.Spec.Description s.GoType = GenStructFromSchema(s) td := TypeDefinition{ @@ -1180,25 +1237,6 @@ func GenerateTypesForOperations(t *template.Template, ops []OperationDefinition) return "", fmt.Errorf("error writing boilerplate to buffer: %w", err) } - // Generate boiler plate for all additional types. - var td []TypeDefinition - for _, op := range ops { - td = append(td, op.TypeDefinitions...) - } - - addProps, err := GenerateAdditionalPropertyBoilerplate(t, td) - if err != nil { - return "", fmt.Errorf("error generating additional properties boilerplate for operations: %w", err) - } - - if _, err := w.WriteString("\n"); err != nil { - return "", fmt.Errorf("error generating additional properties boilerplate for operations: %w", err) - } - - if _, err := w.WriteString(addProps); err != nil { - return "", fmt.Errorf("error generating additional properties boilerplate for operations: %w", err) - } - if err = w.Flush(); err != nil { return "", fmt.Errorf("error flushing output buffer for server interface: %w", err) } diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 4c6fc4517d..bf46a67a63 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -71,16 +71,22 @@ func (s Schema) IsExternalRef() bool { // MarshalJSON/UnmarshalJSON that we need to delegate to. This is true when // the schema is a $ref to a oneOf/anyOf union defined elsewhere. // -// It is deliberately false for inline unions: those are generated by emitting -// the union struct at this schema position, with its own MarshalJSON. The -// template's existing $hasUnionElements branch handles encoding by writing -// .union directly, so no delegation is needed. +// For *local* inline unions it is deliberately false: those are generated by +// emitting the union struct at this schema position, with its own +// MarshalJSON. The template's existing $hasUnionElements branch handles +// encoding by writing .union directly, so no delegation is needed. +// +// For *external* inline unions (the response-root hoist set RefType to a +// type living in an imported package), the strict envelope is rendered as a +// defined type — `type X externalRef0.Y` — and methods on Y don't transfer. +// The .union shortcut also can't reach across packages. So we still need the +// MarshalJSON delegator here, even though UnionElements is non-empty. func (s Schema) HasCustomMarshalJSON() bool { if s.OAPISchema == nil { return false } if len(s.UnionElements) > 0 { - return false + return s.IsExternalRef() } return len(s.OAPISchema.OneOf) > 0 || len(s.OAPISchema.AnyOf) > 0 } diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 3ea88718bb..1beaba0b3f 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -47,6 +47,28 @@ var ( titleCaser = cases.Title(language.English) ) +// isMediaTypeSupported reports whether code generation produces a typed +// body for this media type. Today this is the closed set of JSON / YAML / +// XML variants the response and request templates know how to handle — +// see the typeName switch in GetResponseTypeDefinitions and the body +// definition switch in GenerateBodyDefinitions. A future configuration +// option is intended to let users extend this list. +func isMediaTypeSupported(mediaType string) bool { + switch { + case slices.Contains(contentTypesHalJSON, mediaType): + return true + case slices.Contains(contentTypesJSON, mediaType): + return true + case util.IsMediaTypeJson(mediaType): + return true + case slices.Contains(contentTypesYAML, mediaType): + return true + case slices.Contains(contentTypesXML, mediaType): + return true + } + return false +} + // genParamArgs takes an array of Parameter definition, and generates a valid // Go parameter declaration from them, eg: // ", foo int, bar string, baz float32". The preceding comma is there to save diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl index 8b5b670be6..68ad3d4355 100644 --- a/pkg/codegen/templates/client-with-responses.tmpl +++ b/pkg/codegen/templates/client-with-responses.tmpl @@ -53,12 +53,6 @@ type {{genResponseTypeName $opid | ucFirst}} struct { {{- end}} } -{{- range $responseTypeDefinitions}} - {{- range .AdditionalTypeDefinitions}} - type {{.TypeName}} {{if .IsAlias }}={{end}} {{.Schema.TypeDecl}} - {{- end}} -{{- end}} - // Status returns HTTPResponse.Status func (r {{genResponseTypeName $opid | ucFirst}}) Status() string { if r.HTTPResponse != nil { diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl index bcf372a35c..5f79c84348 100644 --- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl @@ -97,7 +97,7 @@ {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}} {{if .IsJSON }} {{$hasUnionElements := ne 0 (len .Schema.UnionElements)}} - return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if $hasUnionElements}}.union{{end}}) + return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if and $hasUnionElements (not .Schema.IsExternalRef)}}.union{{end}}) {{else if eq .NameTag "Text" -}} _, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}})) return err diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl index f722f51a91..25e7455081 100644 --- a/pkg/codegen/templates/strict/strict-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-interface.tmpl @@ -88,7 +88,7 @@ {{if .IsJSON -}} {{$hasUnionElements := ne 0 (len .Schema.UnionElements) -}} var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if $hasUnionElements}}.union{{end}}); err != nil { + if err := json.NewEncoder(&buf).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if and $hasUnionElements (not .Schema.IsExternalRef)}}.union{{end}}); err != nil { return err } w.Header().Set("Content-Type", {{if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}}) diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl index 75b1d792ec..32d319ed8d 100644 --- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl +++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl @@ -99,7 +99,7 @@ {{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}} {{if .IsJSON -}} {{$hasUnionElements := ne 0 (len .Schema.UnionElements)}} - return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if $hasUnionElements}}.union{{end}}) + return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if and $hasUnionElements (not .Schema.IsExternalRef)}}.union{{end}}) {{else if eq .NameTag "Text" -}} _, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}})) return err