diff --git a/configuration-schema.json b/configuration-schema.json index 43694f9658..a81feefa3c 100644 --- a/configuration-schema.json +++ b/configuration-schema.json @@ -255,7 +255,7 @@ }, "resolve-type-name-collisions": { "type": "boolean", - "description": "When set to true, automatically renames types that collide across different OpenAPI component sections (schemas, parameters, requestBodies, responses, headers) by appending a suffix based on the component section (e.g., 'Parameter', 'Response', 'RequestBody'). Without this, the codegen will error on duplicate type names, requiring manual resolution via x-go-name.", + "description": "When set to true, automatically renames types that collide across different OpenAPI component sections (schemas, parameters, requestBodies, responses, headers) by appending a suffix based on the component section. Also detects collisions between component types and client response wrapper types. Without this, the codegen will error on duplicate type names, requiring manual resolution via x-go-name.", "default": false }, "type-mapping": { diff --git a/internal/test/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index e8102f0d28..df54a6b4ed 100644 --- a/internal/test/externalref/petstore/externalref.gen.go +++ b/internal/test/externalref/petstore/externalref.gen.go @@ -163,6 +163,9 @@ type User struct { Username *string `json:"username,omitempty"` } +// PetRequestBody defines model for Pet. +type PetRequestBody = Pet + // UserArray defines model for UserArray. type UserArray = []User diff --git a/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go b/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go index 780d45e6a7..3ca33f2132 100644 --- a/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go +++ b/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go @@ -31,11 +31,11 @@ type Foo struct { Field1 *string `json:"field1,omitempty"` } -// BazApplicationBarPlusJSON defines model for baz. -type BazApplicationBarPlusJSON = Bar +// BazResponseJSONApplicationBarPlusJSON defines model for baz. +type BazResponseJSONApplicationBarPlusJSON = Bar -// BazApplicationFooPlusJSON defines model for baz. -type BazApplicationFooPlusJSON = Foo +// BazResponseJSON2ApplicationFooPlusJSON defines model for baz. +type BazResponseJSON2ApplicationFooPlusJSON = Foo // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -205,8 +205,8 @@ type TestResponse struct { HTTPResponse *http.Response ApplicationbarJSON200 *Bar ApplicationfooJSON200 *Foo - ApplicationbarJSON201 *BazApplicationBarPlusJSON - ApplicationfooJSON201 *BazApplicationFooPlusJSON + ApplicationbarJSON201 *BazResponseJSONApplicationBarPlusJSON + ApplicationfooJSON201 *BazResponseJSON2ApplicationFooPlusJSON } // Status returns HTTPResponse.Status @@ -256,7 +256,7 @@ func ParseTestResponse(rsp *http.Response) (*TestResponse, error) { response.ApplicationbarJSON200 = &dest case rsp.Header.Get("Content-Type") == "application/bar+json" && rsp.StatusCode == 201: - var dest BazApplicationBarPlusJSON + var dest BazResponseJSONApplicationBarPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -270,7 +270,7 @@ func ParseTestResponse(rsp *http.Response) (*TestResponse, error) { response.ApplicationfooJSON200 = &dest case rsp.Header.Get("Content-Type") == "application/foo+json" && rsp.StatusCode == 201: - var dest BazApplicationFooPlusJSON + var dest BazResponseJSON2ApplicationFooPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -369,7 +369,7 @@ func (response Test200ApplicationFooPlusJSONResponse) VisitTestResponse(w http.R } type Test201ApplicationBarPlusJSONResponse struct { - BazApplicationBarPlusJSONResponse + BazResponseJSONApplicationBarPlusJSONResponse } func (response Test201ApplicationBarPlusJSONResponse) VisitTestResponse(w http.ResponseWriter) error { @@ -380,7 +380,7 @@ func (response Test201ApplicationBarPlusJSONResponse) VisitTestResponse(w http.R } type Test201ApplicationFooPlusJSONResponse struct { - BazApplicationFooPlusJSONResponse + BazResponseJSONApplicationFooPlusJSONResponse } func (response Test201ApplicationFooPlusJSONResponse) VisitTestResponse(w http.ResponseWriter) error { diff --git a/internal/test/issues/issue-200/config.yaml b/internal/test/issues/issue-200/config.yaml deleted file mode 100644 index d68804c987..0000000000 --- a/internal/test/issues/issue-200/config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# yaml-language-server: $schema=../../../../configuration-schema.json -package: issue200 -generate: - models: true -output: issue200.gen.go -output-options: - resolve-type-name-collisions: true diff --git a/internal/test/issues/issue-200/issue200.gen.go b/internal/test/issues/issue-200/issue200.gen.go deleted file mode 100644 index 530c042c7a..0000000000 --- a/internal/test/issues/issue-200/issue200.gen.go +++ /dev/null @@ -1,295 +0,0 @@ -// Package issue200 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 issue200 - -import ( - "encoding/json" - "fmt" -) - -// Bar defines model for Bar. -type Bar struct { - Value *string `json:"value,omitempty"` -} - -// Bar2 defines model for Bar2. -type Bar2 struct { - Value *float32 `json:"value,omitempty"` -} - -// BarParam defines model for BarParam. -type BarParam = []int - -// BarParam2 defines model for BarParam2. -type BarParam2 = []int - -// BarParameter defines model for Bar. -type BarParameter = string - -// BarResponse defines model for Bar. -type BarResponse struct { - Pagination *Bar_Pagination `json:"pagination,omitempty"` - Value1 *Bar `json:"value1,omitempty"` - Value2 *Bar2 `json:"value2,omitempty"` - Value3 *BarParam `json:"value3,omitempty"` - Value4 *BarParam2 `json:"value4,omitempty"` -} - -// Bar_Pagination defines model for Bar.Pagination. -type Bar_Pagination struct { - Page *int `json:"page,omitempty"` - TotalPages *int `json:"totalPages,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -// BarRequestBody defines model for Bar. -type BarRequestBody struct { - Metadata *Bar_Metadata `json:"metadata,omitempty"` - Value *int `json:"value,omitempty"` -} - -// Bar_Metadata defines model for Bar.Metadata. -type Bar_Metadata struct { - Key *string `json:"key,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -// PostFooJSONBody defines parameters for PostFoo. -type PostFooJSONBody struct { - Metadata *PostFooJSONBody_Metadata `json:"metadata,omitempty"` - Value *int `json:"value,omitempty"` -} - -// PostFooParams defines parameters for PostFoo. -type PostFooParams struct { - Bar *Bar `form:"Bar,omitempty" json:"Bar,omitempty"` -} - -// PostFooJSONBody_Metadata defines parameters for PostFoo. -type PostFooJSONBody_Metadata struct { - Key *string `json:"key,omitempty"` - AdditionalProperties map[string]string `json:"-"` -} - -// PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. -type PostFooJSONRequestBody PostFooJSONBody - -// Getter for additional properties for PostFooJSONBody_Metadata. Returns the specified -// element and whether it was found -func (a PostFooJSONBody_Metadata) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for PostFooJSONBody_Metadata -func (a *PostFooJSONBody_Metadata) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for PostFooJSONBody_Metadata to handle AdditionalProperties -func (a *PostFooJSONBody_Metadata) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["key"]; found { - err = json.Unmarshal(raw, &a.Key) - if err != nil { - return fmt.Errorf("error reading 'key': %w", err) - } - delete(object, "key") - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]string) - for fieldName, fieldBuf := range object { - var fieldVal string - 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 PostFooJSONBody_Metadata to handle AdditionalProperties -func (a PostFooJSONBody_Metadata) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Key != nil { - object["key"], err = json.Marshal(a.Key) - if err != nil { - return nil, fmt.Errorf("error marshaling 'key': %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 Bar_Pagination. Returns the specified -// element and whether it was found -func (a Bar_Pagination) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for Bar_Pagination -func (a *Bar_Pagination) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for Bar_Pagination to handle AdditionalProperties -func (a *Bar_Pagination) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["page"]; found { - err = json.Unmarshal(raw, &a.Page) - if err != nil { - return fmt.Errorf("error reading 'page': %w", err) - } - delete(object, "page") - } - - if raw, found := object["totalPages"]; found { - err = json.Unmarshal(raw, &a.TotalPages) - if err != nil { - return fmt.Errorf("error reading 'totalPages': %w", err) - } - delete(object, "totalPages") - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]string) - for fieldName, fieldBuf := range object { - var fieldVal string - 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 Bar_Pagination to handle AdditionalProperties -func (a Bar_Pagination) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Page != nil { - object["page"], err = json.Marshal(a.Page) - if err != nil { - return nil, fmt.Errorf("error marshaling 'page': %w", err) - } - } - - if a.TotalPages != nil { - object["totalPages"], err = json.Marshal(a.TotalPages) - if err != nil { - return nil, fmt.Errorf("error marshaling 'totalPages': %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 Bar_Metadata. Returns the specified -// element and whether it was found -func (a Bar_Metadata) Get(fieldName string) (value string, found bool) { - if a.AdditionalProperties != nil { - value, found = a.AdditionalProperties[fieldName] - } - return -} - -// Setter for additional properties for Bar_Metadata -func (a *Bar_Metadata) Set(fieldName string, value string) { - if a.AdditionalProperties == nil { - a.AdditionalProperties = make(map[string]string) - } - a.AdditionalProperties[fieldName] = value -} - -// Override default JSON handling for Bar_Metadata to handle AdditionalProperties -func (a *Bar_Metadata) UnmarshalJSON(b []byte) error { - object := make(map[string]json.RawMessage) - err := json.Unmarshal(b, &object) - if err != nil { - return err - } - - if raw, found := object["key"]; found { - err = json.Unmarshal(raw, &a.Key) - if err != nil { - return fmt.Errorf("error reading 'key': %w", err) - } - delete(object, "key") - } - - if len(object) != 0 { - a.AdditionalProperties = make(map[string]string) - for fieldName, fieldBuf := range object { - var fieldVal string - 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 Bar_Metadata to handle AdditionalProperties -func (a Bar_Metadata) MarshalJSON() ([]byte, error) { - var err error - object := make(map[string]json.RawMessage) - - if a.Key != nil { - object["key"], err = json.Marshal(a.Key) - if err != nil { - return nil, fmt.Errorf("error marshaling 'key': %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) -} diff --git a/internal/test/issues/issue-200/issue200_test.go b/internal/test/issues/issue-200/issue200_test.go deleted file mode 100644 index 96fdb62e8b..0000000000 --- a/internal/test/issues/issue-200/issue200_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package issue200 - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -// TestDuplicateTypeNamesCompile verifies that when the same name "Bar" is used -// across components/schemas, components/parameters, components/responses, -// components/requestBodies, and components/headers, the codegen produces -// distinct, compilable types with component-based suffixes. -// -// If the auto-rename logic breaks, this test will fail to compile. -func TestDuplicateTypeNamesCompile(t *testing.T) { - // Schema type: Bar (no suffix, first definition wins) - _ = Bar{Value: ptr("hello")} - - // Schema types with unique names (no collision) - _ = Bar2{Value: ptr(float32(1.0))} - _ = BarParam([]int{1, 2, 3}) - _ = BarParam2([]int{4, 5, 6}) - - // Parameter type: BarParameter (was "Bar" in components/parameters) - _ = BarParameter("query-value") - - // Response type: BarResponse (was "Bar" in components/responses) - _ = BarResponse{ - Value1: &Bar{Value: ptr("v1")}, - Value2: &Bar2{Value: ptr(float32(2.0))}, - Value3: &BarParam{1}, - Value4: &BarParam2{2}, - } - - // RequestBody type: BarRequestBody (was "Bar" in components/requestBodies) - _ = BarRequestBody{Value: ptr(42)} - - // Inline nested object with additionalProperties inside a response - // must produce a named AdditionalType (not get silently dropped). - _ = Bar_Pagination{ - Page: ptr(1), - TotalPages: ptr(10), - AdditionalProperties: map[string]string{"cursor": "abc"}, - } - - // Inline nested object with additionalProperties inside a requestBody - // must produce a named AdditionalType (not get silently dropped). - _ = Bar_Metadata{ - Key: ptr("k"), - AdditionalProperties: map[string]string{"extra": "val"}, - } - - // Operation-derived types - _ = PostFooParams{Bar: &Bar{}} - _ = PostFooJSONBody{Value: ptr(99)} - _ = PostFooJSONRequestBody{Value: ptr(100)} - - assert.True(t, true, "all duplicate-named types resolved and compiled") -} - -func ptr[T any](v T) *T { - return &v -} diff --git a/internal/test/issues/issue-200/spec.yaml b/internal/test/issues/issue-200/spec.yaml deleted file mode 100644 index 2a68f71694..0000000000 --- a/internal/test/issues/issue-200/spec.yaml +++ /dev/null @@ -1,96 +0,0 @@ -openapi: 3.0.1 - -info: - title: "Duplicate type names test" - version: 0.0.0 - -paths: - /foo: - post: - operationId: postFoo - parameters: - - $ref: '#/components/parameters/Bar' - requestBody: - $ref: '#/components/requestBodies/Bar' - responses: - 200: - $ref: '#/components/responses/Bar' - -components: - schemas: - Bar: - type: object - properties: - value: - type: string - Bar2: - type: object - properties: - value: - type: number - BarParam: - type: array - items: - type: integer - BarParam2: - type: array - items: - type: integer - - headers: - Bar: - schema: - type: boolean - - parameters: - Bar: - name: Bar - in: query - schema: - type: string - - requestBodies: - Bar: - content: - application/json: - schema: - type: object - properties: - value: - type: integer - metadata: - type: object - properties: - key: - type: string - additionalProperties: - type: string - - responses: - Bar: - description: Bar response - headers: - X-Bar: - $ref: '#/components/headers/Bar' - content: - application/json: - schema: - type: object - properties: - value1: - $ref: '#/components/schemas/Bar' - value2: - $ref: '#/components/schemas/Bar2' - value3: - $ref: '#/components/schemas/BarParam' - value4: - $ref: '#/components/schemas/BarParam2' - pagination: - type: object - properties: - page: - type: integer - totalPages: - type: integer - additionalProperties: - type: string diff --git a/internal/test/name_conflict_resolution/config.yaml b/internal/test/name_conflict_resolution/config.yaml new file mode 100644 index 0000000000..6e173b0a4e --- /dev/null +++ b/internal/test/name_conflict_resolution/config.yaml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=../../../configuration-schema.json +package: nameconflictresolution +generate: + models: true + client: true +output: name_conflict_resolution.gen.go +output-options: + resolve-type-name-collisions: true diff --git a/internal/test/issues/issue-200/doc.go b/internal/test/name_conflict_resolution/doc.go similarity index 78% rename from internal/test/issues/issue-200/doc.go rename to internal/test/name_conflict_resolution/doc.go index 733ebfce17..4d577571ef 100644 --- a/internal/test/issues/issue-200/doc.go +++ b/internal/test/name_conflict_resolution/doc.go @@ -1,3 +1,3 @@ -package issue200 +package nameconflictresolution //go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go new file mode 100644 index 0000000000..068f8e6d4a --- /dev/null +++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go @@ -0,0 +1,3000 @@ +// Package nameconflictresolution 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 nameconflictresolution + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/oapi-codegen/runtime" +) + +// Bar defines model for Bar. +type Bar struct { + Value *string `json:"value,omitempty"` +} + +// Bar2 defines model for Bar2. +type Bar2 struct { + Value *float32 `json:"value,omitempty"` +} + +// CreateItemResponse defines model for CreateItemResponse. +type CreateItemResponse struct { + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` +} + +// GetStatusResponse defines model for GetStatusResponse. +type GetStatusResponse struct { + Status *string `json:"status,omitempty"` + Timestamp *string `json:"timestamp,omitempty"` +} + +// JsonPatch defines model for JsonPatch. +type JsonPatch = []struct { + Op *string `json:"op,omitempty"` + Path *string `json:"path,omitempty"` +} + +// ListItemsResponse defines model for ListItemsResponse. +type ListItemsResponse = string + +// Metadata defines model for Metadata. +type Metadata = string + +// Order defines model for Order. +type Order struct { + Id *string `json:"id,omitempty"` + Product *string `json:"product,omitempty"` +} + +// Outcome defines model for Outcome. +type Outcome struct { + Value *string `json:"value,omitempty"` +} + +// Payload defines model for Payload. +type Payload struct { + Content *string `json:"content,omitempty"` +} + +// Pet defines model for Pet. +type Pet struct { + Id *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` +} + +// QueryResponse defines model for QueryResponse. +type QueryResponse struct { + Results *[]string `json:"results,omitempty"` +} + +// Qux defines model for Qux. +type Qux = CustomQux + +// CustomQux defines model for . +type CustomQux struct { + Label *string `json:"label,omitempty"` +} + +// SpecialName defines model for Renamer. +type SpecialName struct { + Label *string `json:"label,omitempty"` +} + +// Resource defines model for Resource. +type Resource struct { + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Status *string `json:"status,omitempty"` +} + +// ResourceMVO defines model for Resource_MVO. +type ResourceMVO struct { + Name *string `json:"name,omitempty"` + Status *string `json:"status,omitempty"` +} + +// Widget defines model for Widget. +type Widget = string + +// Zap defines model for Zap. +type Zap = string + +// BarParameter defines model for Bar. +type BarParameter = string + +// N200ResourcePatchResponseJSONApplicationJSON defines model for 200Resource_Patch. +type N200ResourcePatchResponseJSONApplicationJSON = Resource + +// N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON defines model for 200Resource_Patch. +type N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON struct { + union json.RawMessage +} + +// N200ResourcePatchApplicationJSONPatchPlusJSON1 defines model for . +type N200ResourcePatchApplicationJSONPatchPlusJSON1 = []Resource + +// N200ResourcePatchApplicationJSONPatchPlusJSON2 defines model for . +type N200ResourcePatchApplicationJSONPatchPlusJSON2 = string + +// N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON defines model for 200Resource_Patch. +type N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON struct { + union json.RawMessage +} + +// N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 defines model for . +type N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 = []Resource + +// N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 defines model for . +type N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 = string + +// N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON defines model for 200Resource_Patch. +type N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON = Resource + +// BarResponse defines model for Bar. +type BarResponse struct { + Value1 *Bar `json:"value1,omitempty"` + Value2 *Bar2 `json:"value2,omitempty"` +} + +// OutcomeResult defines model for Outcome. +type OutcomeResult struct { + Result *string `json:"result,omitempty"` +} + +// QuxResponse defines model for Qux. +type QuxResponse struct { + Data *string `json:"data,omitempty"` +} + +// Renamer defines model for Renamer. +type Renamer struct { + Data *string `json:"data,omitempty"` +} + +// ZapResponse defines model for Zap. +type ZapResponse struct { + Result *string `json:"result,omitempty"` +} + +// BarRequestBody defines model for Bar. +type BarRequestBody struct { + Value *int `json:"value,omitempty"` +} + +// OrderRequestBodyJSON defines model for Order. +type OrderRequestBodyJSON struct { + Id *string `json:"id,omitempty"` + Product *string `json:"product,omitempty"` +} + +// OrderRequestBodyJSON2 defines model for Order. +type OrderRequestBodyJSON2 = []struct { + Op *string `json:"op,omitempty"` + Path *string `json:"path,omitempty"` + Value *string `json:"value,omitempty"` +} + +// OrderRequestBodyJSON3 defines model for Order. +type OrderRequestBodyJSON3 struct { + Product *string `json:"product,omitempty"` +} + +// PayloadBody defines model for Payload. +type PayloadBody struct { + Data *string `json:"data,omitempty"` +} + +// PetRequestBody defines model for Pet. +type PetRequestBody struct { + Name *string `json:"name,omitempty"` + Species *string `json:"species,omitempty"` +} + +// ResourceMVORequestBodyJSON defines model for Resource_MVO. +type ResourceMVORequestBodyJSON = ResourceMVO + +// ResourceMVORequestBodyJSON2 defines model for Resource_MVO. +type ResourceMVORequestBodyJSON2 = JsonPatch + +// ResourceMVORequestBodyJSON3 defines model for Resource_MVO. +type ResourceMVORequestBodyJSON3 = ResourceMVO + +// PostFooJSONBody defines parameters for PostFoo. +type PostFooJSONBody struct { + Value *int `json:"value,omitempty"` +} + +// PostFooParams defines parameters for PostFoo. +type PostFooParams struct { + Bar *BarParameter `form:"bar,omitempty" json:"bar,omitempty"` +} + +// CreateItemJSONBody defines parameters for CreateItem. +type CreateItemJSONBody struct { + Name *string `json:"name,omitempty"` +} + +// CreateOrderJSONBody defines parameters for CreateOrder. +type CreateOrderJSONBody struct { + Id *string `json:"id,omitempty"` + Product *string `json:"product,omitempty"` +} + +// CreateOrderApplicationJSONPatchPlusJSONBody defines parameters for CreateOrder. +type CreateOrderApplicationJSONPatchPlusJSONBody = []struct { + Op *string `json:"op,omitempty"` + Path *string `json:"path,omitempty"` + Value *string `json:"value,omitempty"` +} + +// CreateOrderApplicationMergePatchPlusJSONBody defines parameters for CreateOrder. +type CreateOrderApplicationMergePatchPlusJSONBody struct { + Product *string `json:"product,omitempty"` +} + +// SendPayloadJSONBody defines parameters for SendPayload. +type SendPayloadJSONBody struct { + Data *string `json:"data,omitempty"` +} + +// CreatePetJSONBody defines parameters for CreatePet. +type CreatePetJSONBody struct { + Name *string `json:"name,omitempty"` + Species *string `json:"species,omitempty"` +} + +// QueryJSONBody defines parameters for Query. +type QueryJSONBody struct { + Q *string `json:"q,omitempty"` +} + +// PostFooJSONRequestBody defines body for PostFoo for application/json ContentType. +type PostFooJSONRequestBody PostFooJSONBody + +// CreateItemJSONRequestBody defines body for CreateItem for application/json ContentType. +type CreateItemJSONRequestBody CreateItemJSONBody + +// CreateOrderJSONRequestBody defines body for CreateOrder for application/json ContentType. +type CreateOrderJSONRequestBody CreateOrderJSONBody + +// CreateOrderApplicationJSONPatchPlusJSONRequestBody defines body for CreateOrder for application/json-patch+json ContentType. +type CreateOrderApplicationJSONPatchPlusJSONRequestBody = CreateOrderApplicationJSONPatchPlusJSONBody + +// CreateOrderApplicationMergePatchPlusJSONRequestBody defines body for CreateOrder for application/merge-patch+json ContentType. +type CreateOrderApplicationMergePatchPlusJSONRequestBody CreateOrderApplicationMergePatchPlusJSONBody + +// PostOutcomeJSONRequestBody defines body for PostOutcome for application/json ContentType. +type PostOutcomeJSONRequestBody = Outcome + +// SendPayloadJSONRequestBody defines body for SendPayload for application/json ContentType. +type SendPayloadJSONRequestBody SendPayloadJSONBody + +// CreatePetJSONRequestBody defines body for CreatePet for application/json ContentType. +type CreatePetJSONRequestBody CreatePetJSONBody + +// QueryJSONRequestBody defines body for Query for application/json ContentType. +type QueryJSONRequestBody QueryJSONBody + +// PostQuxJSONRequestBody defines body for PostQux for application/json ContentType. +type PostQuxJSONRequestBody = Qux + +// PostRenamedSchemaJSONRequestBody defines body for PostRenamedSchema for application/json ContentType. +type PostRenamedSchemaJSONRequestBody = SpecialName + +// PatchResourceJSONRequestBody defines body for PatchResource for application/json ContentType. +type PatchResourceJSONRequestBody = ResourceMVO + +// PatchResourceApplicationJSONPatchPlusJSONRequestBody defines body for PatchResource for application/json-patch+json ContentType. +type PatchResourceApplicationJSONPatchPlusJSONRequestBody = JsonPatch + +// PatchResourceApplicationMergePatchPlusJSONRequestBody defines body for PatchResource for application/merge-patch+json ContentType. +type PatchResourceApplicationMergePatchPlusJSONRequestBody = ResourceMVO + +// PostZapJSONRequestBody defines body for PostZap for application/json ContentType. +type PostZapJSONRequestBody = Zap + +// AsResource returns the union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as a Resource +func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) AsResource() (Resource, error) { + var body Resource + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResource overwrites any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as the provided Resource +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) FromResource(v Resource) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResource performs a merge with any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON, using the provided Resource +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MergeResource(v Resource) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsN200ResourcePatchApplicationJSONPatchPlusJSON1 returns the union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as a N200ResourcePatchApplicationJSONPatchPlusJSON1 +func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) AsN200ResourcePatchApplicationJSONPatchPlusJSON1() (N200ResourcePatchApplicationJSONPatchPlusJSON1, error) { + var body N200ResourcePatchApplicationJSONPatchPlusJSON1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromN200ResourcePatchApplicationJSONPatchPlusJSON1 overwrites any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as the provided N200ResourcePatchApplicationJSONPatchPlusJSON1 +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) FromN200ResourcePatchApplicationJSONPatchPlusJSON1(v N200ResourcePatchApplicationJSONPatchPlusJSON1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeN200ResourcePatchApplicationJSONPatchPlusJSON1 performs a merge with any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchPlusJSON1 +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MergeN200ResourcePatchApplicationJSONPatchPlusJSON1(v N200ResourcePatchApplicationJSONPatchPlusJSON1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsN200ResourcePatchApplicationJSONPatchPlusJSON2 returns the union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as a N200ResourcePatchApplicationJSONPatchPlusJSON2 +func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) AsN200ResourcePatchApplicationJSONPatchPlusJSON2() (N200ResourcePatchApplicationJSONPatchPlusJSON2, error) { + var body N200ResourcePatchApplicationJSONPatchPlusJSON2 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromN200ResourcePatchApplicationJSONPatchPlusJSON2 overwrites any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as the provided N200ResourcePatchApplicationJSONPatchPlusJSON2 +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) FromN200ResourcePatchApplicationJSONPatchPlusJSON2(v N200ResourcePatchApplicationJSONPatchPlusJSON2) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeN200ResourcePatchApplicationJSONPatchPlusJSON2 performs a merge with any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchPlusJSON2 +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MergeN200ResourcePatchApplicationJSONPatchPlusJSON2(v N200ResourcePatchApplicationJSONPatchPlusJSON2) 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 N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsResource returns the union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as a Resource +func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) AsResource() (Resource, error) { + var body Resource + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromResource overwrites any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as the provided Resource +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) FromResource(v Resource) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeResource performs a merge with any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON, using the provided Resource +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MergeResource(v Resource) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON1 returns the union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as a N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 +func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON1() (N200ResourcePatchApplicationJSONPatchQueryPlusJSON1, error) { + var body N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON1 overwrites any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON1(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON1 performs a merge with any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON1(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON2 returns the union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as a N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 +func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON2() (N200ResourcePatchApplicationJSONPatchQueryPlusJSON2, error) { + var body N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON2 overwrites any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON2(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON2) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON2 performs a merge with any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON2(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON2) 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 N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) 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 { + // ListEntities request + ListEntities(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostFooWithBody request with any body + PostFooWithBody(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostFoo(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // ListItems request + ListItems(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateItemWithBody request with any body + CreateItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateItem(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreateOrderWithBody request with any body + CreateOrderWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateOrder(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateOrderWithApplicationJSONPatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateOrderWithApplicationMergePatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetOutcome request + GetOutcome(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostOutcomeWithBody request with any body + PostOutcomeWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostOutcome(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // SendPayloadWithBody request with any body + SendPayloadWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + SendPayload(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // CreatePetWithBody request with any body + CreatePetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreatePet(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // QueryWithBody request with any body + QueryWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + Query(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetQux request + GetQux(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostQuxWithBody request with any body + PostQuxWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostQux(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetRenamedSchema request + GetRenamedSchema(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostRenamedSchemaWithBody request with any body + PostRenamedSchemaWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostRenamedSchema(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PatchResourceWithBody request with any body + PatchResourceWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PatchResource(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + PatchResourceWithApplicationJSONPatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + PatchResourceWithApplicationMergePatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetStatus request + GetStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetZap request + GetZap(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) + + // PostZapWithBody request with any body + PostZapWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + PostZap(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) ListEntities(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListEntitiesRequest(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) PostFooWithBody(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostFooRequestWithBody(c.Server, params, 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) PostFoo(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostFooRequest(c.Server, params, 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) ListItems(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListItemsRequest(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) CreateItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateItemRequestWithBody(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) CreateItem(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateItemRequest(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) CreateOrderWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateOrderRequestWithBody(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) CreateOrder(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateOrderRequest(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) CreateOrderWithApplicationJSONPatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateOrderRequestWithApplicationJSONPatchPlusJSONBody(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) CreateOrderWithApplicationMergePatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateOrderRequestWithApplicationMergePatchPlusJSONBody(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) GetOutcome(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetOutcomeRequest(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) PostOutcomeWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostOutcomeRequestWithBody(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) PostOutcome(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostOutcomeRequest(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) SendPayloadWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSendPayloadRequestWithBody(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) SendPayload(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSendPayloadRequest(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) CreatePetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreatePetRequestWithBody(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) CreatePet(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreatePetRequest(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) QueryWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewQueryRequestWithBody(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) Query(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewQueryRequest(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) GetQux(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetQuxRequest(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) PostQuxWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostQuxRequestWithBody(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) PostQux(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostQuxRequest(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) GetRenamedSchema(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetRenamedSchemaRequest(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) PostRenamedSchemaWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostRenamedSchemaRequestWithBody(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) PostRenamedSchema(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostRenamedSchemaRequest(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) PatchResourceWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPatchResourceRequestWithBody(c.Server, id, 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) PatchResource(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPatchResourceRequest(c.Server, id, 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) PatchResourceWithApplicationJSONPatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPatchResourceRequestWithApplicationJSONPatchPlusJSONBody(c.Server, id, 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) PatchResourceWithApplicationMergePatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPatchResourceRequestWithApplicationMergePatchPlusJSONBody(c.Server, id, 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) GetStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetStatusRequest(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) GetZap(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetZapRequest(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) PostZapWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostZapRequestWithBody(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) PostZap(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewPostZapRequest(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) +} + +// NewListEntitiesRequest generates requests for ListEntities +func NewListEntitiesRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/entities") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostFooRequest calls the generic PostFoo builder with application/json body +func NewPostFooRequest(server string, params *PostFooParams, body PostFooJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostFooRequestWithBody(server, params, "application/json", bodyReader) +} + +// NewPostFooRequestWithBody generates requests for PostFoo with any type of body +func NewPostFooRequestWithBody(server string, params *PostFooParams, 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("/foo") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Bar != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "bar", *params.Bar, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewListItemsRequest generates requests for ListItems +func NewListItemsRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/items") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewCreateItemRequest calls the generic CreateItem builder with application/json body +func NewCreateItemRequest(server string, body CreateItemJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateItemRequestWithBody(server, "application/json", bodyReader) +} + +// NewCreateItemRequestWithBody generates requests for CreateItem with any type of body +func NewCreateItemRequestWithBody(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("/items") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewCreateOrderRequest calls the generic CreateOrder builder with application/json body +func NewCreateOrderRequest(server string, body CreateOrderJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateOrderRequestWithBody(server, "application/json", bodyReader) +} + +// NewCreateOrderRequestWithApplicationJSONPatchPlusJSONBody calls the generic CreateOrder builder with application/json-patch+json body +func NewCreateOrderRequestWithApplicationJSONPatchPlusJSONBody(server string, body CreateOrderApplicationJSONPatchPlusJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateOrderRequestWithBody(server, "application/json-patch+json", bodyReader) +} + +// NewCreateOrderRequestWithApplicationMergePatchPlusJSONBody calls the generic CreateOrder builder with application/merge-patch+json body +func NewCreateOrderRequestWithApplicationMergePatchPlusJSONBody(server string, body CreateOrderApplicationMergePatchPlusJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateOrderRequestWithBody(server, "application/merge-patch+json", bodyReader) +} + +// NewCreateOrderRequestWithBody generates requests for CreateOrder with any type of body +func NewCreateOrderRequestWithBody(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("/orders") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetOutcomeRequest generates requests for GetOutcome +func NewGetOutcomeRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/outcome") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostOutcomeRequest calls the generic PostOutcome builder with application/json body +func NewPostOutcomeRequest(server string, body PostOutcomeJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostOutcomeRequestWithBody(server, "application/json", bodyReader) +} + +// NewPostOutcomeRequestWithBody generates requests for PostOutcome with any type of body +func NewPostOutcomeRequestWithBody(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("/outcome") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewSendPayloadRequest calls the generic SendPayload builder with application/json body +func NewSendPayloadRequest(server string, body SendPayloadJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewSendPayloadRequestWithBody(server, "application/json", bodyReader) +} + +// NewSendPayloadRequestWithBody generates requests for SendPayload with any type of body +func NewSendPayloadRequestWithBody(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("/payload") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewCreatePetRequest calls the generic CreatePet builder with application/json body +func NewCreatePetRequest(server string, body CreatePetJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreatePetRequestWithBody(server, "application/json", bodyReader) +} + +// NewCreatePetRequestWithBody generates requests for CreatePet with any type of body +func NewCreatePetRequestWithBody(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("/pets") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewQueryRequest calls the generic Query builder with application/json body +func NewQueryRequest(server string, body QueryJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewQueryRequestWithBody(server, "application/json", bodyReader) +} + +// NewQueryRequestWithBody generates requests for Query with any type of body +func NewQueryRequestWithBody(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("/query") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetQuxRequest generates requests for GetQux +func NewGetQuxRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/qux") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostQuxRequest calls the generic PostQux builder with application/json body +func NewPostQuxRequest(server string, body PostQuxJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostQuxRequestWithBody(server, "application/json", bodyReader) +} + +// NewPostQuxRequestWithBody generates requests for PostQux with any type of body +func NewPostQuxRequestWithBody(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("/qux") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetRenamedSchemaRequest generates requests for GetRenamedSchema +func NewGetRenamedSchemaRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/renamed-schema") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostRenamedSchemaRequest calls the generic PostRenamedSchema builder with application/json body +func NewPostRenamedSchemaRequest(server string, body PostRenamedSchemaJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostRenamedSchemaRequestWithBody(server, "application/json", bodyReader) +} + +// NewPostRenamedSchemaRequestWithBody generates requests for PostRenamedSchema with any type of body +func NewPostRenamedSchemaRequestWithBody(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("/renamed-schema") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewPatchResourceRequest calls the generic PatchResource builder with application/json body +func NewPatchResourceRequest(server string, id string, body PatchResourceJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPatchResourceRequestWithBody(server, id, "application/json", bodyReader) +} + +// NewPatchResourceRequestWithApplicationJSONPatchPlusJSONBody calls the generic PatchResource builder with application/json-patch+json body +func NewPatchResourceRequestWithApplicationJSONPatchPlusJSONBody(server string, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPatchResourceRequestWithBody(server, id, "application/json-patch+json", bodyReader) +} + +// NewPatchResourceRequestWithApplicationMergePatchPlusJSONBody calls the generic PatchResource builder with application/merge-patch+json body +func NewPatchResourceRequestWithApplicationMergePatchPlusJSONBody(server string, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPatchResourceRequestWithBody(server, id, "application/merge-patch+json", bodyReader) +} + +// NewPatchResourceRequestWithBody generates requests for PatchResource with any type of body +func NewPatchResourceRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithOptions("simple", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""}) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/resources/%s", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("PATCH", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewGetStatusRequest generates requests for GetStatus +func NewGetStatusRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/status") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetZapRequest generates requests for GetZap +func NewGetZapRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/zap") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewPostZapRequest calls the generic PostZap builder with application/json body +func NewPostZapRequest(server string, body PostZapJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewPostZapRequestWithBody(server, "application/json", bodyReader) +} + +// NewPostZapRequestWithBody generates requests for PostZap with any type of body +func NewPostZapRequestWithBody(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("/zap") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + 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 { + // ListEntitiesWithResponse request + ListEntitiesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListEntitiesResponse, error) + + // PostFooWithBodyWithResponse request with any body + PostFooWithBodyWithResponse(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostFooResponse, error) + + PostFooWithResponse(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*PostFooResponse, error) + + // ListItemsWithResponse request + ListItemsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListItemsResponse2, error) + + // CreateItemWithBodyWithResponse request with any body + CreateItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error) + + CreateItemWithResponse(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error) + + // CreateOrderWithBodyWithResponse request with any body + CreateOrderWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) + + CreateOrderWithResponse(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) + + CreateOrderWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) + + CreateOrderWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) + + // GetOutcomeWithResponse request + GetOutcomeWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetOutcomeResponse, error) + + // PostOutcomeWithBodyWithResponse request with any body + PostOutcomeWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error) + + PostOutcomeWithResponse(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error) + + // SendPayloadWithBodyWithResponse request with any body + SendPayloadWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error) + + SendPayloadWithResponse(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error) + + // CreatePetWithBodyWithResponse request with any body + CreatePetWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreatePetResponse, error) + + CreatePetWithResponse(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*CreatePetResponse, error) + + // QueryWithBodyWithResponse request with any body + QueryWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*QueryResponse2, error) + + QueryWithResponse(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*QueryResponse2, error) + + // GetQuxWithResponse request + GetQuxWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetQuxResponse, error) + + // PostQuxWithBodyWithResponse request with any body + PostQuxWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostQuxResponse, error) + + PostQuxWithResponse(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*PostQuxResponse, error) + + // GetRenamedSchemaWithResponse request + GetRenamedSchemaWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetRenamedSchemaResponse, error) + + // PostRenamedSchemaWithBodyWithResponse request with any body + PostRenamedSchemaWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error) + + PostRenamedSchemaWithResponse(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error) + + // PatchResourceWithBodyWithResponse request with any body + PatchResourceWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) + + PatchResourceWithResponse(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) + + PatchResourceWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) + + PatchResourceWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) + + // GetStatusWithResponse request + GetStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStatusResponse2, error) + + // GetZapWithResponse request + GetZapWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetZapResponse, error) + + // PostZapWithBodyWithResponse request with any body + PostZapWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostZapResponse, error) + + PostZapWithResponse(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*PostZapResponse, error) +} + +type ListEntitiesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Data *[]Widget `json:"data,omitempty"` + Metadata *Metadata `json:"metadata,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r ListEntitiesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ListEntitiesResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostFooResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *BarResponse +} + +// Status returns HTTPResponse.Status +func (r PostFooResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostFooResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type ListItemsResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *ListItemsResponse +} + +// Status returns HTTPResponse.Status +func (r ListItemsResponse2) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ListItemsResponse2) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateItemResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *CreateItemResponse +} + +// Status returns HTTPResponse.Status +func (r CreateItemResponse2) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateItemResponse2) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateOrderResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Order +} + +// Status returns HTTPResponse.Status +func (r CreateOrderResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateOrderResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetOutcomeResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *OutcomeResult +} + +// Status returns HTTPResponse.Status +func (r GetOutcomeResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetOutcomeResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostOutcomeResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostOutcomeResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostOutcomeResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type SendPayloadResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Payload +} + +// Status returns HTTPResponse.Status +func (r SendPayloadResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r SendPayloadResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreatePetResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Pet +} + +// Status returns HTTPResponse.Status +func (r CreatePetResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreatePetResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type QueryResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *QueryResponse +} + +// Status returns HTTPResponse.Status +func (r QueryResponse2) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r QueryResponse2) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetQuxResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *QuxResponse +} + +// Status returns HTTPResponse.Status +func (r GetQuxResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetQuxResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostQuxResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostQuxResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostQuxResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetRenamedSchemaResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Renamer +} + +// Status returns HTTPResponse.Status +func (r GetRenamedSchemaResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetRenamedSchemaResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostRenamedSchemaResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostRenamedSchemaResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostRenamedSchemaResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PatchResourceResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *N200ResourcePatchResponseJSONApplicationJSON + ApplicationjsonPatchJSON200 *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON + 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 { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PatchResourceResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetStatusResponse2 struct { + Body []byte + HTTPResponse *http.Response + JSON200 *GetStatusResponse +} + +// Status returns HTTPResponse.Status +func (r GetStatusResponse2) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetStatusResponse2) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetZapResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *ZapResponse +} + +// Status returns HTTPResponse.Status +func (r GetZapResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetZapResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type PostZapResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r PostZapResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r PostZapResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ListEntitiesWithResponse request returning *ListEntitiesResponse +func (c *ClientWithResponses) ListEntitiesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListEntitiesResponse, error) { + rsp, err := c.ListEntities(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseListEntitiesResponse(rsp) +} + +// PostFooWithBodyWithResponse request with arbitrary body returning *PostFooResponse +func (c *ClientWithResponses) PostFooWithBodyWithResponse(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostFooResponse, error) { + rsp, err := c.PostFooWithBody(ctx, params, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostFooResponse(rsp) +} + +func (c *ClientWithResponses) PostFooWithResponse(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*PostFooResponse, error) { + rsp, err := c.PostFoo(ctx, params, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostFooResponse(rsp) +} + +// ListItemsWithResponse request returning *ListItemsResponse2 +func (c *ClientWithResponses) ListItemsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListItemsResponse2, error) { + rsp, err := c.ListItems(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseListItemsResponse2(rsp) +} + +// CreateItemWithBodyWithResponse request with arbitrary body returning *CreateItemResponse2 +func (c *ClientWithResponses) CreateItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error) { + rsp, err := c.CreateItemWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateItemResponse2(rsp) +} + +func (c *ClientWithResponses) CreateItemWithResponse(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error) { + rsp, err := c.CreateItem(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateItemResponse2(rsp) +} + +// CreateOrderWithBodyWithResponse request with arbitrary body returning *CreateOrderResponse +func (c *ClientWithResponses) CreateOrderWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) { + rsp, err := c.CreateOrderWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateOrderResponse(rsp) +} + +func (c *ClientWithResponses) CreateOrderWithResponse(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) { + rsp, err := c.CreateOrder(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateOrderResponse(rsp) +} + +func (c *ClientWithResponses) CreateOrderWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) { + rsp, err := c.CreateOrderWithApplicationJSONPatchPlusJSONBody(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateOrderResponse(rsp) +} + +func (c *ClientWithResponses) CreateOrderWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) { + rsp, err := c.CreateOrderWithApplicationMergePatchPlusJSONBody(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateOrderResponse(rsp) +} + +// GetOutcomeWithResponse request returning *GetOutcomeResponse +func (c *ClientWithResponses) GetOutcomeWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetOutcomeResponse, error) { + rsp, err := c.GetOutcome(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetOutcomeResponse(rsp) +} + +// PostOutcomeWithBodyWithResponse request with arbitrary body returning *PostOutcomeResponse +func (c *ClientWithResponses) PostOutcomeWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error) { + rsp, err := c.PostOutcomeWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostOutcomeResponse(rsp) +} + +func (c *ClientWithResponses) PostOutcomeWithResponse(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error) { + rsp, err := c.PostOutcome(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostOutcomeResponse(rsp) +} + +// SendPayloadWithBodyWithResponse request with arbitrary body returning *SendPayloadResponse +func (c *ClientWithResponses) SendPayloadWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error) { + rsp, err := c.SendPayloadWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSendPayloadResponse(rsp) +} + +func (c *ClientWithResponses) SendPayloadWithResponse(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error) { + rsp, err := c.SendPayload(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSendPayloadResponse(rsp) +} + +// CreatePetWithBodyWithResponse request with arbitrary body returning *CreatePetResponse +func (c *ClientWithResponses) CreatePetWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreatePetResponse, error) { + rsp, err := c.CreatePetWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreatePetResponse(rsp) +} + +func (c *ClientWithResponses) CreatePetWithResponse(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*CreatePetResponse, error) { + rsp, err := c.CreatePet(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreatePetResponse(rsp) +} + +// QueryWithBodyWithResponse request with arbitrary body returning *QueryResponse2 +func (c *ClientWithResponses) QueryWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*QueryResponse2, error) { + rsp, err := c.QueryWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseQueryResponse2(rsp) +} + +func (c *ClientWithResponses) QueryWithResponse(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*QueryResponse2, error) { + rsp, err := c.Query(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseQueryResponse2(rsp) +} + +// GetQuxWithResponse request returning *GetQuxResponse +func (c *ClientWithResponses) GetQuxWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetQuxResponse, error) { + rsp, err := c.GetQux(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetQuxResponse(rsp) +} + +// PostQuxWithBodyWithResponse request with arbitrary body returning *PostQuxResponse +func (c *ClientWithResponses) PostQuxWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostQuxResponse, error) { + rsp, err := c.PostQuxWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostQuxResponse(rsp) +} + +func (c *ClientWithResponses) PostQuxWithResponse(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*PostQuxResponse, error) { + rsp, err := c.PostQux(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostQuxResponse(rsp) +} + +// GetRenamedSchemaWithResponse request returning *GetRenamedSchemaResponse +func (c *ClientWithResponses) GetRenamedSchemaWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetRenamedSchemaResponse, error) { + rsp, err := c.GetRenamedSchema(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetRenamedSchemaResponse(rsp) +} + +// PostRenamedSchemaWithBodyWithResponse request with arbitrary body returning *PostRenamedSchemaResponse +func (c *ClientWithResponses) PostRenamedSchemaWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error) { + rsp, err := c.PostRenamedSchemaWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostRenamedSchemaResponse(rsp) +} + +func (c *ClientWithResponses) PostRenamedSchemaWithResponse(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error) { + rsp, err := c.PostRenamedSchema(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostRenamedSchemaResponse(rsp) +} + +// PatchResourceWithBodyWithResponse request with arbitrary body returning *PatchResourceResponse +func (c *ClientWithResponses) PatchResourceWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) { + rsp, err := c.PatchResourceWithBody(ctx, id, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePatchResourceResponse(rsp) +} + +func (c *ClientWithResponses) PatchResourceWithResponse(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) { + rsp, err := c.PatchResource(ctx, id, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePatchResourceResponse(rsp) +} + +func (c *ClientWithResponses) PatchResourceWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) { + rsp, err := c.PatchResourceWithApplicationJSONPatchPlusJSONBody(ctx, id, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePatchResourceResponse(rsp) +} + +func (c *ClientWithResponses) PatchResourceWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) { + rsp, err := c.PatchResourceWithApplicationMergePatchPlusJSONBody(ctx, id, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePatchResourceResponse(rsp) +} + +// GetStatusWithResponse request returning *GetStatusResponse2 +func (c *ClientWithResponses) GetStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStatusResponse2, error) { + rsp, err := c.GetStatus(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetStatusResponse2(rsp) +} + +// GetZapWithResponse request returning *GetZapResponse +func (c *ClientWithResponses) GetZapWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetZapResponse, error) { + rsp, err := c.GetZap(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseGetZapResponse(rsp) +} + +// PostZapWithBodyWithResponse request with arbitrary body returning *PostZapResponse +func (c *ClientWithResponses) PostZapWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostZapResponse, error) { + rsp, err := c.PostZapWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostZapResponse(rsp) +} + +func (c *ClientWithResponses) PostZapWithResponse(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*PostZapResponse, error) { + rsp, err := c.PostZap(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParsePostZapResponse(rsp) +} + +// ParseListEntitiesResponse parses an HTTP response from a ListEntitiesWithResponse call +func ParseListEntitiesResponse(rsp *http.Response) (*ListEntitiesResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ListEntitiesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Data *[]Widget `json:"data,omitempty"` + Metadata *Metadata `json:"metadata,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParsePostFooResponse parses an HTTP response from a PostFooWithResponse call +func ParsePostFooResponse(rsp *http.Response) (*PostFooResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostFooResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest BarResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseListItemsResponse2 parses an HTTP response from a ListItemsWithResponse call +func ParseListItemsResponse2(rsp *http.Response) (*ListItemsResponse2, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ListItemsResponse2{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest ListItemsResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseCreateItemResponse2 parses an HTTP response from a CreateItemWithResponse call +func ParseCreateItemResponse2(rsp *http.Response) (*CreateItemResponse2, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateItemResponse2{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest CreateItemResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseCreateOrderResponse parses an HTTP response from a CreateOrderWithResponse call +func ParseCreateOrderResponse(rsp *http.Response) (*CreateOrderResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateOrderResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Order + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetOutcomeResponse parses an HTTP response from a GetOutcomeWithResponse call +func ParseGetOutcomeResponse(rsp *http.Response) (*GetOutcomeResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetOutcomeResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest OutcomeResult + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParsePostOutcomeResponse parses an HTTP response from a PostOutcomeWithResponse call +func ParsePostOutcomeResponse(rsp *http.Response) (*PostOutcomeResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostOutcomeResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseSendPayloadResponse parses an HTTP response from a SendPayloadWithResponse call +func ParseSendPayloadResponse(rsp *http.Response) (*SendPayloadResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &SendPayloadResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Payload + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseCreatePetResponse parses an HTTP response from a CreatePetWithResponse call +func ParseCreatePetResponse(rsp *http.Response) (*CreatePetResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreatePetResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Pet + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseQueryResponse2 parses an HTTP response from a QueryWithResponse call +func ParseQueryResponse2(rsp *http.Response) (*QueryResponse2, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &QueryResponse2{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest QueryResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetQuxResponse parses an HTTP response from a GetQuxWithResponse call +func ParseGetQuxResponse(rsp *http.Response) (*GetQuxResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetQuxResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest QuxResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParsePostQuxResponse parses an HTTP response from a PostQuxWithResponse call +func ParsePostQuxResponse(rsp *http.Response) (*PostQuxResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostQuxResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParseGetRenamedSchemaResponse parses an HTTP response from a GetRenamedSchemaWithResponse call +func ParseGetRenamedSchemaResponse(rsp *http.Response) (*GetRenamedSchemaResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetRenamedSchemaResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Renamer + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParsePostRenamedSchemaResponse parses an HTTP response from a PostRenamedSchemaWithResponse call +func ParsePostRenamedSchemaResponse(rsp *http.Response) (*PostRenamedSchemaResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostRenamedSchemaResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} + +// ParsePatchResourceResponse parses an HTTP response from a PatchResourceWithResponse call +func ParsePatchResourceResponse(rsp *http.Response) (*PatchResourceResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PatchResourceResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case rsp.Header.Get("Content-Type") == "application/json-patch+json" && rsp.StatusCode == 200: + var dest N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationjsonPatchJSON200 = &dest + + case rsp.Header.Get("Content-Type") == "application/json-patch-query+json" && rsp.StatusCode == 200: + var dest N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationjsonPatchQueryJSON200 = &dest + + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200: + var dest N200ResourcePatchResponseJSONApplicationJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case rsp.Header.Get("Content-Type") == "application/merge-patch+json" && rsp.StatusCode == 200: + var dest N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationmergePatchJSON200 = &dest + + } + + return response, nil +} + +// ParseGetStatusResponse2 parses an HTTP response from a GetStatusWithResponse call +func ParseGetStatusResponse2(rsp *http.Response) (*GetStatusResponse2, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetStatusResponse2{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest GetStatusResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParseGetZapResponse parses an HTTP response from a GetZapWithResponse call +func ParseGetZapResponse(rsp *http.Response) (*GetZapResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetZapResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest ZapResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + +// ParsePostZapResponse parses an HTTP response from a PostZapWithResponse call +func ParsePostZapResponse(rsp *http.Response) (*PostZapResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &PostZapResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, nil +} diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution_test.go b/internal/test/name_conflict_resolution/name_conflict_resolution_test.go new file mode 100644 index 0000000000..158f56f3f4 --- /dev/null +++ b/internal/test/name_conflict_resolution/name_conflict_resolution_test.go @@ -0,0 +1,460 @@ +package nameconflictresolution + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestCrossSectionCollisions verifies Pattern A: when the same name "Bar" +// appears in schemas, parameters, requestBodies, and responses, the resolver +// keeps the bare name for the component schema and suffixes the others. +// +// Covers issues: #200, #254, #407, #1881, PR #292 +func TestCrossSectionCollisions(t *testing.T) { + // Schema type keeps bare name "Bar" + bar := Bar{Value: ptr("hello")} + assert.Equal(t, "hello", *bar.Value) + + // No collision for Bar2 + bar2 := Bar2{Value: ptr(float32(1.5))} + assert.Equal(t, float32(1.5), *bar2.Value) + + // Parameter type gets "Parameter" suffix + param := BarParameter("query-value") + assert.Equal(t, "query-value", string(param)) + + // RequestBody type gets "RequestBody" suffix + reqBody := BarRequestBody{Value: ptr(42)} + assert.Equal(t, 42, *reqBody.Value) + + // Response type gets "Response" suffix + resp := BarResponse{ + Value1: &Bar{Value: ptr("v1")}, + Value2: &Bar2{Value: ptr(float32(2.0))}, + } + assert.Equal(t, "v1", *resp.Value1.Value) + assert.Equal(t, float32(2.0), *resp.Value2.Value) + + // PostFoo wrapper does not collide (unique name PostFooResponse) + var wrapper PostFooResponse + assert.Nil(t, wrapper.JSON200) + // JSON200 field points to the response type BarResponse (not schema type Bar) + wrapper.JSON200 = &resp + assert.Equal(t, "v1", *wrapper.JSON200.Value1.Value) +} + +// TestSchemaVsClientWrapper verifies Pattern B: schema "CreateItemResponse" +// collides with the client wrapper for operation "createItem". The schema +// keeps the bare name; the wrapper gets numeric fallback "CreateItemResponse2". +// +// Covers issues: #1474, #1713, #1450 +func TestSchemaVsClientWrapper(t *testing.T) { + // Schema type keeps bare name + schema := CreateItemResponse{ + Id: ptr("item-1"), + Name: ptr("Widget"), + } + assert.Equal(t, "item-1", *schema.Id) + assert.Equal(t, "Widget", *schema.Name) + + // Client wrapper gets numeric fallback + var wrapper CreateItemResponse2 + assert.Nil(t, wrapper.Body) + assert.Nil(t, wrapper.HTTPResponse) + assert.Nil(t, wrapper.JSON200) + + // JSON200 field references the schema type, not the wrapper itself + wrapper.JSON200 = &schema + assert.Equal(t, "item-1", *wrapper.JSON200.Id) +} + +// TestSchemaAliasVsClientWrapper verifies Pattern C: schema "ListItemsResponse" +// (a string alias) collides with the client wrapper for operation "listItems". +// The schema keeps the bare name; the wrapper gets "ListItemsResponse2". +// +// Covers issue: #1357 +func TestSchemaAliasVsClientWrapper(t *testing.T) { + // Schema type is a string alias + var schema ListItemsResponse = "item-list" + assert.Equal(t, "item-list", schema) + + // Client wrapper gets numeric fallback + var wrapper ListItemsResponse2 + assert.Nil(t, wrapper.Body) + assert.Nil(t, wrapper.HTTPResponse) + assert.Nil(t, wrapper.JSON200) + + // JSON200 field references the schema type (string alias) + wrapper.JSON200 = &schema + assert.Equal(t, "item-list", *wrapper.JSON200) +} + +// TestOperationNameMatchesSchema verifies Pattern D: schema "QueryResponse" +// collides with the client wrapper for operation "query" (which generates +// "QueryResponse"). The schema keeps the bare name; the wrapper gets +// "QueryResponse2". +// +// Covers issue: #255 +func TestOperationNameMatchesSchema(t *testing.T) { + // Schema type keeps bare name + schema := QueryResponse{ + Results: &[]string{"result1", "result2"}, + } + assert.Len(t, *schema.Results, 2) + + // Client wrapper gets numeric fallback + var wrapper QueryResponse2 + assert.Nil(t, wrapper.JSON200) + + // JSON200 field references the schema type + wrapper.JSON200 = &schema + assert.Len(t, *wrapper.JSON200.Results, 2) +} + +// TestSchemaMatchesOpResponse verifies Pattern E: schema "GetStatusResponse" +// collides with the client wrapper for operation "getStatus" (which generates +// "GetStatusResponse"). The schema keeps the bare name; the wrapper gets +// "GetStatusResponse2". +// +// Covers issues: #2097, #899 +func TestSchemaMatchesOpResponse(t *testing.T) { + // Schema type keeps bare name + schema := GetStatusResponse{ + Status: ptr("healthy"), + Timestamp: ptr("2025-01-01T00:00:00Z"), + } + assert.Equal(t, "healthy", *schema.Status) + assert.Equal(t, "2025-01-01T00:00:00Z", *schema.Timestamp) + + // Client wrapper gets numeric fallback + var wrapper GetStatusResponse2 + assert.Nil(t, wrapper.JSON200) + + // JSON200 field references the schema type + wrapper.JSON200 = &schema + assert.Equal(t, "healthy", *wrapper.JSON200.Status) +} + +// TestMultipleJsonContentTypes verifies Pattern H: schema "Order" collides with +// requestBody "Order" which has 3 content types that all contain "json": +// - application/json +// - application/merge-patch+json +// - application/json-patch+json +// +// All three map to the same "JSON" short name via contentTypeSuffix(), which +// would trigger an infinite oscillation between context suffix ("RequestBody") +// and content type suffix ("JSON") strategies if applied per-group. The global +// phase approach lets numeric fallback break the cycle. +// +// Expected types: +// - Order struct (schema keeps bare name) +// - OrderRequestBodyJSON struct (application/json requestBody) +// - OrderRequestBodyJSON2 []struct (application/json-patch+json, numeric fallback) +// - OrderRequestBodyJSON3 struct (application/merge-patch+json, numeric fallback) +// +// Covers: PR #2213 (multiple JSON content types in requestBody) +func TestMultipleJsonContentTypes(t *testing.T) { + // Schema type keeps bare name "Order" + order := Order{ + Id: ptr("order-1"), + Product: ptr("Widget"), + } + assert.Equal(t, "order-1", *order.Id) + assert.Equal(t, "Widget", *order.Product) + + // The 3 requestBody content types should each get a unique name. + // They all collide on "OrderRequestBodyJSON", so numeric fallback kicks in. + // The type names below are compile-time assertions that all 3 exist and are distinct. + + // application/json requestBody + jsonBody := OrderRequestBodyJSON{ + Id: ptr("order-2"), + Product: ptr("Gadget"), + } + assert.Equal(t, "order-2", *jsonBody.Id) + + // application/json-patch+json requestBody (numeric fallback, array type alias) + var jsonPatch OrderRequestBodyJSON2 + assert.Nil(t, jsonPatch) + + // application/merge-patch+json requestBody (numeric fallback) + mergePatch := OrderRequestBodyJSON3{ + Product: ptr("Gadget-patched"), + } + assert.Equal(t, "Gadget-patched", *mergePatch.Product) + + // CreateOrder wrapper should not collide + var wrapper CreateOrderResponse + assert.Nil(t, wrapper.JSON200) + wrapper.JSON200 = &order + assert.Equal(t, "order-1", *wrapper.JSON200.Id) +} + +// TestRequestBodyVsSchema verifies that "Pet" in schemas and requestBodies +// resolves correctly: the schema keeps bare name "Pet", the requestBody +// gets "PetRequestBody". +// +// Covers issues: #254, #407 +func TestRequestBodyVsSchema(t *testing.T) { + // Schema type keeps bare name + pet := Pet{ + Id: ptr(1), + Name: ptr("Fluffy"), + } + assert.Equal(t, 1, *pet.Id) + assert.Equal(t, "Fluffy", *pet.Name) + + // RequestBody type gets "RequestBody" suffix + petReqBody := PetRequestBody{ + Name: ptr("Fluffy"), + Species: ptr("cat"), + } + assert.Equal(t, "Fluffy", *petReqBody.Name) + assert.Equal(t, "cat", *petReqBody.Species) + + // CreatePet wrapper doesn't collide (unique name CreatePetResponse) + var wrapper CreatePetResponse + assert.Nil(t, wrapper.JSON200) + + // JSON200 field references the schema type Pet + wrapper.JSON200 = &pet + assert.Equal(t, "Fluffy", *wrapper.JSON200.Name) +} + +// TestRefTargetPicksUpRename verifies that when an operation references a +// renamed component via $ref, the generated wrapper type uses the resolved +// (renamed) type, not the original spec name. +func TestRefTargetPicksUpRename(t *testing.T) { + // When postFoo references $ref: '#/components/responses/Bar', + // and response Bar is renamed to BarResponse, the wrapper's + // JSON200 field must use BarResponse (not Bar). + barResp := BarResponse{ + Value1: &Bar{Value: ptr("v1")}, + Value2: &Bar2{Value: ptr(float32(2.0))}, + } + var wrapper PostFooResponse + wrapper.JSON200 = &barResp // compile-time: JSON200 must be *BarResponse + assert.Equal(t, "v1", *wrapper.JSON200.Value1.Value) + assert.Equal(t, float32(2.0), *wrapper.JSON200.Value2.Value) +} + +// TestExtGoTypeNameWithCollisionResolver verifies that when a component schema +// has x-go-type-name: CustomQux and collides with a response "Qux", the +// collision resolver controls the top-level Go type names while x-go-type-name +// controls the underlying type definition. +// +// Expected types: +// - CustomQux struct (underlying type from x-go-type-name) +// - Qux = CustomQux (schema keeps bare name, aliased) +// - QuxResponse struct (response gets suffixed) +func TestExtGoTypeNameWithCollisionResolver(t *testing.T) { + // CustomQux is the underlying struct created by x-go-type-name + custom := CustomQux{Label: ptr("hello")} + assert.Equal(t, "hello", *custom.Label) + + // Qux is a type alias for CustomQux (schema keeps bare name) + var qux Qux = custom //nolint:staticcheck // explicit type needed to prove Qux aliases CustomQux + assert.Equal(t, "hello", *qux.Label) + + // QuxResponse is the response type (response gets suffixed) + quxResp := QuxResponse{Data: ptr("response-data")} + assert.Equal(t, "response-data", *quxResp.Data) + + // GetQuxResponse client wrapper's JSON200 field uses *QuxResponse + var wrapper GetQuxResponse + assert.Nil(t, wrapper.JSON200) + wrapper.JSON200 = &quxResp + assert.Equal(t, "response-data", *wrapper.JSON200.Data) +} + +// TestExtGoTypeWithCollisionResolver verifies that when a component schema has +// x-go-type: string and collides with a response "Zap", the collision resolver +// controls the top-level Go type names while x-go-type controls the target type. +// +// Expected types: +// - Zap = string (schema keeps bare name, x-go-type controls target) +// - ZapResponse struct (response gets suffixed) +func TestExtGoTypeWithCollisionResolver(t *testing.T) { + // Zap is a string type alias (x-go-type controls the target) + var zap Zap = "test-value" + assert.Equal(t, "test-value", string(zap)) + + // ZapResponse is the response type (response gets suffixed) + zapResp := ZapResponse{Result: ptr("response-result")} + assert.Equal(t, "response-result", *zapResp.Result) + + // GetZapResponse client wrapper's JSON200 field uses *ZapResponse + var wrapper GetZapResponse + assert.Nil(t, wrapper.JSON200) + wrapper.JSON200 = &zapResp + assert.Equal(t, "response-result", *wrapper.JSON200.Result) +} + +// TestInlineResponseWithRefProperties verifies Pattern I (oapi-codegen-exp#14): +// when a response has an inline object whose properties contain $refs to component +// schemas with x-go-type, the property-level refs must NOT produce duplicate type +// declarations. The component schemas keep their type aliases (Widget = string, +// Metadata = string), and the inline response object gets its own struct type. +// +// Covers: oapi-codegen-exp#14 +func TestInlineResponseWithRefProperties(t *testing.T) { + // Component schemas with x-go-type: string produce type aliases + var widget Widget = "widget-value" + assert.Equal(t, "widget-value", string(widget)) + + var metadata Metadata = "metadata-value" + assert.Equal(t, "metadata-value", string(metadata)) + + // The inline response object should have fields typed by the component aliases. + // The client wrapper for listEntities should exist and have a JSON200 field + // pointing to the inline response type. + var wrapper ListEntitiesResponse + assert.Nil(t, wrapper.JSON200) +} + +// TestDuplicateOneOfMembersAcrossContentTypes verifies Pattern J: +// when a response has multiple JSON content types (e.g., application/json-patch+json +// and application/json-patch-query+json) that share an identical oneOf schema with +// inline (non-$ref) members, the codegen must not emit duplicate type declarations +// for those inline members. +// +// Additionally, when a requestBody shares its name with a component schema and its +// content schemas $ref the component schema (plus one $refs a different schema), +// the collision resolver must assign unique names. +// +// Expected types: +// - ResourceMVO struct (schema keeps bare name) +// - Resource struct (no collision) +// - JsonPatch []struct (no collision) +// - ResourceMVORequestBodyJSON = ResourceMVO (requestBody application/json) +// - ResourceMVORequestBodyJSON2 = JsonPatch (requestBody application/json-patch+json) +// - ResourceMVORequestBodyJSON3 = ResourceMVO (requestBody application/merge-patch+json) +// - PatchResourceResponse struct (client response wrapper) +// - inline oneOf member types (must not be duplicated) +func TestDuplicateOneOfMembersAcrossContentTypes(t *testing.T) { + // Schema types keep bare names + resource := Resource{ + Id: ptr("res-1"), + Name: ptr("MyResource"), + Status: ptr("active"), + } + assert.Equal(t, "res-1", *resource.Id) + + resourceMVO := ResourceMVO{ + Name: ptr("MyResource"), + Status: ptr("active"), + } + assert.Equal(t, "MyResource", *resourceMVO.Name) + + // RequestBody collision resolution: schema "Resource_MVO" keeps bare name, + // requestBody content types get suffixed. + var reqBodyJSON ResourceMVORequestBodyJSON + reqBodyJSON.Name = ptr("test") + assert.Equal(t, "test", *reqBodyJSON.Name) + + var reqBodyPatch ResourceMVORequestBodyJSON2 + assert.Nil(t, reqBodyPatch) // JsonPatch alias (slice type) + + var reqBodyMerge ResourceMVORequestBodyJSON3 + reqBodyMerge.Name = ptr("merge") + assert.Equal(t, "merge", *reqBodyMerge.Name) + + // Client response wrapper should exist. The primary assertion here + // is that the package compiles — no duplicate oneOf member types and + // no undefined response type names. + var wrapper PatchResourceResponse + assert.Nil(t, wrapper.Body) + assert.Nil(t, wrapper.HTTPResponse) +} + +// TestXGoNameOnSchemaPreserved verifies Pattern K: when a component schema +// has x-go-name, the collision resolver must use the x-go-name value as the +// schema's type name (pinned), not the original spec name. +// +// Schema "Renamer" has x-go-name: "SpecialName" and shares a name with +// response "Renamer". With correct x-go-name handling the schema becomes +// "SpecialName", so no collision exists and the response keeps "Renamer". +// +// Expected types: +// - SpecialName struct (schema "Renamer" pinned by x-go-name) +// - Renamer struct (response "Renamer" — no collision) +// +// Covers: PR #2213 review finding (x-go-name not respected by resolver) +func TestXGoNameOnSchemaPreserved(t *testing.T) { + // Schema "Renamer" should use its x-go-name "SpecialName" + schema := SpecialName{Label: ptr("test-label")} + assert.Equal(t, "test-label", *schema.Label) + + // Response "Renamer" should keep its bare name (no collision with schema) + resp := Renamer{Data: ptr("response-data")} + assert.Equal(t, "response-data", *resp.Data) + + // Client wrapper for getRenamedSchema should reference the response type + var wrapper GetRenamedSchemaResponse + assert.Nil(t, wrapper.JSON200) + wrapper.JSON200 = &resp + assert.Equal(t, "response-data", *wrapper.JSON200.Data) +} + +// TestXGoNameOnResponsePreserved verifies Pattern L: when a component response +// has x-go-name, the collision resolver must use the x-go-name value as the +// response's type name (pinned), not the original spec name. +// +// Response "Outcome" has x-go-name: "OutcomeResult" and shares a name with +// schema "Outcome". With correct x-go-name handling the response becomes +// "OutcomeResult", so no collision exists and the schema keeps "Outcome". +// +// Expected types: +// - Outcome struct (schema keeps bare name — no collision) +// - OutcomeResult struct (response "Outcome" pinned by x-go-name) +// +// Covers: PR #2213 review finding (x-go-name not respected by resolver) +func TestXGoNameOnResponsePreserved(t *testing.T) { + // Schema "Outcome" should keep its bare name + schema := Outcome{Value: ptr("some-value")} + assert.Equal(t, "some-value", *schema.Value) + + // Response "Outcome" should use its x-go-name "OutcomeResult" + resp := OutcomeResult{Result: ptr("outcome-data")} + assert.Equal(t, "outcome-data", *resp.Result) + + // Client wrapper for getOutcome should reference the response type + var wrapper GetOutcomeResponse + assert.Nil(t, wrapper.JSON200) + wrapper.JSON200 = &resp + assert.Equal(t, "outcome-data", *wrapper.JSON200.Result) +} + +// TestXGoNameOnRequestBodyPreserved verifies Pattern M: when a component +// requestBody has x-go-name, the collision resolver must use the x-go-name +// value as the requestBody's type name (pinned), not the original spec name. +// +// RequestBody "Payload" has x-go-name: "PayloadBody" and shares a name with +// schema "Payload". With correct x-go-name handling the requestBody becomes +// "PayloadBody", so no collision exists and the schema keeps "Payload". +// +// Expected types: +// - Payload struct (schema keeps bare name — no collision) +// - PayloadBody struct (requestBody "Payload" pinned by x-go-name) +// +// Covers: PR #2213 review finding (x-go-name not respected by resolver) +func TestXGoNameOnRequestBodyPreserved(t *testing.T) { + // Schema "Payload" should keep its bare name + schema := Payload{Content: ptr("payload-content")} + assert.Equal(t, "payload-content", *schema.Content) + + // RequestBody "Payload" should use its x-go-name "PayloadBody" + reqBody := PayloadBody{Data: ptr("body-data")} + assert.Equal(t, "body-data", *reqBody.Data) + + // Client wrapper for sendPayload should reference the schema type + var wrapper SendPayloadResponse + assert.Nil(t, wrapper.JSON200) + wrapper.JSON200 = &schema + assert.Equal(t, "payload-content", *wrapper.JSON200.Content) +} + +func ptr[T any](v T) *T { + return &v +} diff --git a/internal/test/name_conflict_resolution/spec.yaml b/internal/test/name_conflict_resolution/spec.yaml new file mode 100644 index 0000000000..6cebbb9668 --- /dev/null +++ b/internal/test/name_conflict_resolution/spec.yaml @@ -0,0 +1,607 @@ +openapi: 3.0.1 + +info: + title: "Comprehensive name collision resolution test" + description: | + Exercises all documented name collision patterns across issues and PRs: + #200, #254, #255, #292, #407, #899, #1357, #1450, #1474, #1713, #1881, #2097, #2213 + Also covers oapi-codegen-exp#14 (inline response object with $ref properties). + Patterns K/L/M cover x-go-name preservation during collision resolution (PR #2213 review). + version: 0.0.0 + +paths: + # Pattern A: Cross-section collision (issues #200, #254, #407, #1881, PR #292) + # "Bar" appears in schemas, parameters, requestBodies, responses, and headers. + /foo: + post: + operationId: postFoo + parameters: + - $ref: '#/components/parameters/Bar' + requestBody: + $ref: '#/components/requestBodies/Bar' + responses: + 200: + $ref: '#/components/responses/Bar' + + # Pattern B: Schema vs client wrapper (issues #1474, #1713, #1450) + # Schema "CreateItemResponse" collides with createItem wrapper. + /items: + post: + operationId: createItem + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CreateItemResponse' + + # Pattern C: Schema alias vs client wrapper (issue #1357) + # Schema "ListItemsResponse" (string alias) collides with listItems wrapper. + get: + operationId: listItems + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ListItemsResponse' + + # Pattern D: Operation name = schema response name (issue #255) + # Schema "QueryResponse" collides with query wrapper. + /query: + post: + operationId: query + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + q: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/QueryResponse' + + # Pattern E: Schema matches op+Response (issues #2097, #899) + # Schema "GetStatusResponse" collides with getStatus wrapper. + /status: + get: + operationId: getStatus + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/GetStatusResponse' + + # Pattern F: x-go-type-name extension + cross-section collision + # Schema "Qux" has x-go-type-name and collides with response "Qux". + /qux: + get: + operationId: getQux + responses: + '200': + $ref: '#/components/responses/Qux' + post: + operationId: postQux + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Qux' + responses: + '200': + description: OK + + # Pattern G: x-go-type extension + cross-section collision + # Schema "Zap" has x-go-type and collides with response "Zap". + /zap: + get: + operationId: getZap + responses: + '200': + $ref: '#/components/responses/Zap' + post: + operationId: postZap + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Zap' + responses: + '200': + description: OK + + # Pattern H: Multiple JSON content types in requestBody (PR #2213) + # "Order" appears in schemas and requestBodies. The requestBody has 3 content + # types that all contain "json" and collapse to the same "JSON" short name: + # application/json, application/merge-patch+json, application/json-patch+json + # This triggers an infinite oscillation between context suffix and content type + # suffix strategies unless the numeric fallback can break the cycle. + /orders: + post: + operationId: createOrder + requestBody: + $ref: '#/components/requestBodies/Order' + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + + # Pattern I: Inline response object with $ref properties to x-go-type schemas + # (oapi-codegen-exp#14). The response has an inline object with properties that + # $ref component schemas carrying x-go-type. Each property ref should use the + # component schema's type alias, not produce duplicate type declarations. + /entities: + get: + operationId: listEntities + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Widget' + metadata: + $ref: '#/components/schemas/Metadata' + + # Pattern J: Duplicate inline oneOf members across response content types + # A PATCH operation returns multiple JSON content types + # (application/json, application/json-patch+json, application/json-patch-query+json, + # application/merge-patch+json). The json-patch and json-patch-query variants + # share an identical oneOf schema with inline (non-$ref) members. The codegen + # must not emit duplicate type declarations for those inline members. + # + # Additionally, the requestBody shares the same name as a component schema + # ("Resource_MVO") where the requestBody content schemas $ref the component + # schema, and one content type $refs a different schema. + /resources/{id}: + patch: + operationId: patchResource + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + $ref: '#/components/requestBodies/Resource_MVO' + responses: + '200': + $ref: '#/components/responses/200Resource_Patch' + + # Pattern K: x-go-name on schema — resolver must preserve user-specified names + # Schema "Renamer" has x-go-name: "SpecialName". Response "Renamer" also exists. + # The resolver should use "SpecialName" for the schema (pinned by x-go-name) + # and "Renamer" for the response (no collision since the schema is "SpecialName"). + # Covers: PR #2213 review finding (x-go-name not respected by resolver) + /renamed-schema: + get: + operationId: getRenamedSchema + responses: + '200': + $ref: '#/components/responses/Renamer' + post: + operationId: postRenamedSchema + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Renamer' + responses: + '200': + description: OK + + # Pattern L: x-go-name on response — resolver must preserve user-specified names + # Response "Outcome" has x-go-name: "OutcomeResult". Schema "Outcome" also exists. + # The resolver should use "OutcomeResult" for the response (pinned by x-go-name) + # and "Outcome" for the schema (no collision since the response is "OutcomeResult"). + # Covers: PR #2213 review finding (x-go-name not respected by resolver) + /outcome: + get: + operationId: getOutcome + responses: + '200': + $ref: '#/components/responses/Outcome' + post: + operationId: postOutcome + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Outcome' + responses: + '200': + description: OK + + # Pattern M: x-go-name on requestBody — resolver must preserve user-specified names + # RequestBody "Payload" has x-go-name: "PayloadBody". Schema "Payload" also exists. + # The resolver should use "PayloadBody" for the requestBody (pinned by x-go-name) + # and "Payload" for the schema (no collision since the requestBody is "PayloadBody"). + # Covers: PR #2213 review finding (x-go-name not respected by resolver) + /payload: + post: + operationId: sendPayload + requestBody: + $ref: '#/components/requestBodies/Payload' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Payload' + + # Cross-section: requestBody vs schema (issues #254, #407) + # "Pet" appears in both schemas and requestBodies. + /pets: + post: + operationId: createPet + requestBody: + $ref: '#/components/requestBodies/Pet' + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + +components: + schemas: + Bar: + type: object + properties: + value: + type: string + + Bar2: + type: object + properties: + value: + type: number + + CreateItemResponse: + type: object + properties: + id: + type: string + name: + type: string + + ListItemsResponse: + type: string + + QueryResponse: + type: object + properties: + results: + type: array + items: + type: string + + GetStatusResponse: + type: object + properties: + status: + type: string + timestamp: + type: string + + # Pattern H: Schema "Order" collides with requestBody "Order" which has + # 3 content types that all map to the "JSON" short name. + Order: + type: object + properties: + id: + type: string + product: + type: string + + Pet: + type: object + properties: + id: + type: integer + name: + type: string + + # Pattern I: schemas with x-go-type used as $ref targets in inline response properties. + # (oapi-codegen-exp#14) + Widget: + type: object + x-go-type: string + properties: + id: + type: string + + Metadata: + type: object + x-go-type: string + properties: + total: + type: integer + + # Pattern J: schema "Resource_MVO" collides with requestBody "Resource_MVO". + # The requestBody's content schemas $ref the component schema, plus one + # content type $refs a different schema (JsonPatch). The response for the + # PATCH operation has multiple JSON content types, two of which share an + # identical oneOf schema with inline members. + Resource_MVO: + type: object + properties: + name: + type: string + status: + type: string + + Resource: + type: object + properties: + id: + type: string + name: + type: string + status: + type: string + + JsonPatch: + type: array + items: + type: object + properties: + op: + type: string + path: + type: string + + # Pattern K: x-go-name on schema — should be pinned as "SpecialName" + Renamer: + x-go-name: SpecialName + type: object + properties: + label: + type: string + + # Pattern L: schema "Outcome" (no x-go-name — keeps bare name) + Outcome: + type: object + properties: + value: + type: string + + # Pattern M: schema "Payload" (no x-go-name — keeps bare name) + Payload: + type: object + properties: + content: + type: string + + # Pattern F: x-go-type-name extension + cross-section collision + # Schema "Qux" has x-go-type-name: CustomQux and collides with response "Qux". + Qux: + type: object + x-go-type-name: CustomQux + properties: + label: + type: string + + # Pattern G: x-go-type extension + cross-section collision + # Schema "Zap" has x-go-type: string and collides with response "Zap". + Zap: + type: object + x-go-type: string + properties: + unused: + type: string + + parameters: + Bar: + name: bar + in: query + schema: + type: string + + requestBodies: + Bar: + content: + application/json: + schema: + type: object + properties: + value: + type: integer + + # Pattern H: requestBody "Order" with 3 content types that all contain "json" + # and collapse to the same "JSON" suffix via contentTypeSuffix(). + Order: + content: + application/json: + schema: + type: object + properties: + id: + type: string + product: + type: string + application/merge-patch+json: + schema: + type: object + properties: + product: + type: string + application/json-patch+json: + schema: + type: array + items: + type: object + properties: + op: + type: string + path: + type: string + value: + type: string + + Pet: + content: + application/json: + schema: + type: object + properties: + name: + type: string + species: + type: string + + # Pattern M: requestBody "Payload" has x-go-name — should be pinned as "PayloadBody" + Payload: + x-go-name: PayloadBody + content: + application/json: + schema: + type: object + properties: + data: + type: string + + # Pattern J: requestBody "Resource_MVO" shares name with schema "Resource_MVO". + # Content schemas $ref the component schema, except json-patch which $refs JsonPatch. + Resource_MVO: + content: + application/json: + schema: + $ref: '#/components/schemas/Resource_MVO' + application/merge-patch+json: + schema: + $ref: '#/components/schemas/Resource_MVO' + application/json-patch+json: + schema: + $ref: '#/components/schemas/JsonPatch' + + headers: + Bar: + schema: + type: boolean + + responses: + Bar: + description: Bar response + headers: + X-Bar: + $ref: '#/components/headers/Bar' + content: + application/json: + schema: + type: object + properties: + value1: + $ref: '#/components/schemas/Bar' + value2: + $ref: '#/components/schemas/Bar2' + + # Pattern K: response "Renamer" — no x-go-name, should keep bare name "Renamer" + # because the schema collision is avoided by the schema's x-go-name: SpecialName. + Renamer: + description: A Renamer response + content: + application/json: + schema: + type: object + properties: + data: + type: string + + # Pattern L: response "Outcome" has x-go-name — should be pinned as "OutcomeResult" + Outcome: + x-go-name: OutcomeResult + description: An Outcome response + content: + application/json: + schema: + type: object + properties: + result: + type: string + + Qux: + description: A Qux response + content: + application/json: + schema: + type: object + properties: + data: + type: string + + Zap: + description: A Zap response + content: + application/json: + schema: + type: object + properties: + result: + type: string + + # Pattern J: response with multiple JSON content types where json-patch + # and json-patch-query variants share an identical oneOf schema with + # inline (non-$ref) members. The codegen must not emit duplicate type + # declarations for those inline members. + 200Resource_Patch: + description: Patch success + content: + application/json: + schema: + $ref: '#/components/schemas/Resource' + application/merge-patch+json: + schema: + $ref: '#/components/schemas/Resource' + application/json-patch+json: + schema: + oneOf: + - $ref: '#/components/schemas/Resource' + - type: array + items: + $ref: '#/components/schemas/Resource' + - type: string + nullable: true + application/json-patch-query+json: + schema: + oneOf: + - $ref: '#/components/schemas/Resource' + - type: array + items: + $ref: '#/components/schemas/Resource' + - type: string + nullable: true diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go index b189ff5adf..71f65e7cd5 100644 --- a/internal/test/strict-server/client/client.gen.go +++ b/internal/test/strict-server/client/client.gen.go @@ -1457,7 +1457,7 @@ type UnionExampleResponse struct { union json.RawMessage } } -type UnionExample2000 = string +type UnionExample200ApplicationJSON0 = string // Status returns HTTPResponse.Status func (r UnionExampleResponse) Status() string { diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 0f38b6ff7f..038d5c9fa1 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -54,6 +54,12 @@ var globalState struct { initialismsMap map[string]string // typeMapping is the merged type mapping (defaults + user overrides). typeMapping TypeMapping + // resolvedNames maps schema path strings (e.g. "components/schemas/Pet") + // to their resolved Go type names, assigned by the multi-pass name resolver. + resolvedNames map[string]string + // resolvedClientWrapperNames maps operationID to the resolved Go type name + // for client response wrapper types (e.g., "createChatCompletion" -> "CreateChatCompletionResponseWrapper"). + resolvedClientWrapperNames map[string]string } // goImport represents a go package to be imported in the generated code @@ -176,6 +182,28 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { globalState.initialismsMap = makeInitialismsMap(opts.OutputOptions.AdditionalInitialisms) + // Multi-pass name resolution: gather all schemas, then resolve names globally. + // Only enabled when resolve-type-name-collisions is set. + if true { // HACK + gathered := GatherSchemas(spec, opts) + globalState.resolvedNames = ResolveNames(gathered) + // Build a separate operationID -> wrapper name lookup for genResponseTypeName. + // Keys must use the normalized operationID (via nameNormalizer) because + // OperationDefinition.OperationId is normalized before templates run. + globalState.resolvedClientWrapperNames = make(map[string]string) + for _, gs := range gathered { + if gs.Context == ContextClientResponseWrapper && gs.OperationID != "" { + if name, ok := globalState.resolvedNames[gs.Path.String()]; ok { + normalizedOpID := nameNormalizer(gs.OperationID) + globalState.resolvedClientWrapperNames[normalizedOpID] = name + } + } + } + } else { + globalState.resolvedNames = nil + globalState.resolvedClientWrapperNames = nil + } + // This creates the golang templates text package TemplateFunctions["opts"] = func() Configuration { return globalState.options } t := template.New("oapi-codegen").Funcs(TemplateFunctions) @@ -614,6 +642,10 @@ func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3. return nil, fmt.Errorf("error making name for components/schemas/%s: %w", schemaName, err) } + if resolved := resolvedNameForComponent("schemas", schemaName); resolved != "" { + goTypeName = resolved + } + types = append(types, TypeDefinition{ JsonName: schemaName, TypeName: goTypeName, @@ -642,6 +674,10 @@ func GenerateTypesForParameters(t *template.Template, params map[string]*openapi return nil, fmt.Errorf("error making name for components/parameters/%s: %w", paramName, err) } + if resolved := resolvedNameForComponent("parameters", paramName); resolved != "" { + goTypeName = resolved + } + typeDef := TypeDefinition{ JsonName: paramName, Schema: goType, @@ -689,7 +725,22 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response continue } - goType, err := GenerateGoSchema(response.Schema, []string{responseName}) + // When a response has multiple JSON content types, include the + // content type in the schema path so that inline types (e.g., + // oneOf union members) get unique names per content type. + // See the matching logic in GetResponseTypeDefinitions. + // + // 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{responseName} + if jsonCount > 1 && true { // HACK + schemaPath = append(schemaPath, mediaTypeToCamelCase(mediaType)) + } + goType, err := GenerateGoSchema(response.Schema, schemaPath) if err != nil { return nil, fmt.Errorf("error generating Go type for schema in response %s: %w", responseName, err) } @@ -699,7 +750,9 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response return nil, fmt.Errorf("error making name for components/responses/%s: %w", responseName, err) } - goType.DefinedComp = ComponentTypeResponse + if resolved := resolvedNameForComponent("responses", responseName, mediaType); resolved != "" { + goTypeName = resolved + } typeDef := TypeDefinition{ JsonName: responseName, @@ -738,7 +791,8 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open // As for responses, we will only generate Go code for JSON bodies, // the other body formats are up to the user. response := requestBodyRef.Value - for mediaType, body := range response.Content { + for _, mediaType := range SortedMapKeys(response.Content) { + body := response.Content[mediaType] if !util.IsMediaTypeJson(mediaType) { continue } @@ -753,7 +807,9 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open return nil, fmt.Errorf("error making name for components/schemas/%s: %w", requestBodyName, err) } - goType.DefinedComp = ComponentTypeRequestBody + if resolved := resolvedNameForComponent("requestBodies", requestBodyName, mediaType); resolved != "" { + goTypeName = resolved + } typeDef := TypeDefinition{ JsonName: requestBodyName, @@ -782,15 +838,11 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) m := map[string]TypeDefinition{} var ts []TypeDefinition - if globalState.options.OutputOptions.ResolveTypeNameCollisions { - types = FixDuplicateTypeNames(types) - } - for _, typ := range types { if prevType, found := m[typ.TypeName]; found { - // If type names collide after auto-rename, we need to see if they - // refer to the same exact type definition, in which case, we can - // de-dupe. If they don't match, we error out. + // If type names collide, we need to see if they refer to the same + // exact type definition, in which case, we can de-dupe. If they + // don't match, we error out. if TypeDefinitionsEquivalent(prevType, typ) { continue } @@ -812,6 +864,63 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) return GenerateTemplates([]string{"typedef.tmpl"}, t, context) } +// resolvedNameForComponent looks up the resolved Go type name for a component +// identified by its section (e.g., "schemas", "parameters") and name. +// For content-bearing sections (responses, requestBodies), an optional +// contentType can be provided to match the exact media type entry. +// Returns empty string if no resolved name is available. +func resolvedNameForComponent(section, name string, contentType ...string) string { + if len(globalState.resolvedNames) == 0 { + return "" + } + + // Direct key match for schemas, parameters, headers + key := "components/" + section + "/" + name + if resolved, ok := globalState.resolvedNames[key]; ok { + return resolved + } + + // For responses and requestBodies, the path includes content type info. + // If a specific content type was provided, do an exact match. + if len(contentType) > 0 && contentType[0] != "" { + exactKey := key + "/content/" + contentType[0] + if resolved, ok := globalState.resolvedNames[exactKey]; ok { + return resolved + } + } + + // Fall back to prefix match for callers that don't specify content type. + // Sort matching keys so the result is deterministic across runs. + prefix := key + "/" + var matches []string + for k := range globalState.resolvedNames { + if strings.HasPrefix(k, prefix) { + matches = append(matches, k) + } + } + if len(matches) > 0 { + if len(matches) > 1 { + sort.Strings(matches) + } + return globalState.resolvedNames[matches[0]] + } + + return "" +} + +// resolvedNameForRefPath looks up the resolved Go type name for a $ref path +// like "#/components/responses/Foo", optionally scoped to a specific content type. +func resolvedNameForRefPath(refPath, contentType string) string { + if len(globalState.resolvedNames) == 0 || !strings.HasPrefix(refPath, "#/") { + return "" + } + parts := strings.Split(refPath, "/") + if len(parts) != 4 || parts[1] != "components" { + return "" + } + return resolvedNameForComponent(parts[2], parts[3], contentType) +} + func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error) { enums := []EnumDefinition{} diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go index 4598bb04ad..6f4df06a0f 100644 --- a/pkg/codegen/configuration.go +++ b/pkg/codegen/configuration.go @@ -305,8 +305,10 @@ type OutputOptions struct { // types that collide across different OpenAPI component sections // (schemas, parameters, requestBodies, responses, headers) by appending // a suffix based on the component section (e.g., "Parameter", "Response", - // "RequestBody"). Without this, the codegen will error on duplicate type - // names, requiring manual resolution via x-go-name. + // "RequestBody"). It also detects collisions between component types and + // client response wrapper types (e.g., issue #1474). Without this, the + // codegen will error on duplicate type names, requiring manual resolution + // via x-go-name. ResolveTypeNameCollisions bool `yaml:"resolve-type-name-collisions,omitempty"` // TypeMapping allows customizing OpenAPI type/format to Go type mappings. diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go index 6bc6bff144..dbf6611f4d 100644 --- a/pkg/codegen/extension.go +++ b/pkg/codegen/extension.go @@ -5,7 +5,10 @@ import ( ) const ( - // extPropGoType overrides the generated type definition. + // extPropGoType overrides the generated type definition. When + // resolve-type-name-collisions is enabled, the collision resolver + // controls the final Go type name; this extension controls what + // that name aliases or refers to. extPropGoType = "x-go-type" // extPropGoTypeSkipOptionalPointer specifies that optional fields should // be the type itself instead of a pointer to the type. @@ -14,7 +17,10 @@ const ( extPropGoImport = "x-go-type-import" // extGoName is used to override a field name extGoName = "x-go-name" - // extGoTypeName is used to override a generated typename for something. + // extGoTypeName overrides a generated typename. When + // resolve-type-name-collisions is enabled, the collision resolver + // controls the top-level Go type name; this extension controls + // the name of the underlying type definition that gets aliased. extGoTypeName = "x-go-type-name" extPropGoJsonIgnore = "x-go-json-ignore" extPropOmitEmpty = "x-omitempty" diff --git a/pkg/codegen/gather.go b/pkg/codegen/gather.go new file mode 100644 index 0000000000..84bd7e55df --- /dev/null +++ b/pkg/codegen/gather.go @@ -0,0 +1,331 @@ +package codegen + +import ( + "fmt" + "sort" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/oapi-codegen/oapi-codegen/v2/pkg/util" +) + +// SchemaPath represents the document location of a schema, e.g. +// ["components", "schemas", "Pet", "properties", "name"]. +type SchemaPath []string + +// String returns the path joined with "/". +func (sp SchemaPath) String() string { + return strings.Join(sp, "/") +} + +// SchemaContext identifies where in the OpenAPI document a schema was found. +type SchemaContext int + +const ( + ContextComponentSchema SchemaContext = iota + ContextComponentParameter + ContextComponentRequestBody + ContextComponentResponse + ContextComponentHeader + ContextOperationParameter + ContextOperationRequestBody + ContextOperationResponse + ContextClientResponseWrapper +) + +// String returns a human-readable name for the context. +func (sc SchemaContext) String() string { + switch sc { + case ContextComponentSchema: + return "Schema" + case ContextComponentParameter: + return "Parameter" + case ContextComponentRequestBody: + return "RequestBody" + case ContextComponentResponse: + return "Response" + case ContextComponentHeader: + return "Header" + case ContextOperationParameter: + return "OperationParameter" + case ContextOperationRequestBody: + return "OperationRequestBody" + case ContextOperationResponse: + return "OperationResponse" + case ContextClientResponseWrapper: + return "ClientResponseWrapper" + default: + return "Unknown" + } +} + +// Suffix returns the suffix to use for collision resolution. +func (sc SchemaContext) Suffix() string { + switch sc { + case ContextComponentSchema: + return "Schema" + case ContextComponentParameter, ContextOperationParameter: + return "Parameter" + case ContextComponentRequestBody, ContextOperationRequestBody: + return "RequestBody" + case ContextComponentResponse, ContextOperationResponse: + return "Response" + case ContextComponentHeader: + return "Header" + case ContextClientResponseWrapper: + return "Response" + default: + return "" + } +} + +// GatheredSchema represents a schema discovered during the gather pass, +// along with its document location and context metadata. +type GatheredSchema struct { + Path SchemaPath + Context SchemaContext + Ref string // $ref string if this is a reference + Schema *openapi3.Schema // The resolved schema value + OperationID string // Enclosing operation's ID, if any + ContentType string // Media type, if from request/response body + StatusCode string // HTTP status code, if from a response + ParamIndex int // Parameter index within an operation + ComponentName string // The component name (e.g., "Bar" for components/schemas/Bar) + GoNameOverride string // x-go-name override from the component or its parent container +} + +// IsComponentSchema returns true if this schema came from components/schemas. +func (gs *GatheredSchema) IsComponentSchema() bool { + return gs.Context == ContextComponentSchema +} + +// GatherSchemas walks the entire OpenAPI spec and collects all schemas that +// will need Go type names. This is the first pass of the multi-pass resolution. +func GatherSchemas(spec *openapi3.T, opts Configuration) []*GatheredSchema { + var schemas []*GatheredSchema + + if spec.Components != nil { + schemas = append(schemas, gatherComponentSchemas(spec.Components)...) + schemas = append(schemas, gatherComponentParameters(spec.Components)...) + schemas = append(schemas, gatherComponentResponses(spec.Components)...) + schemas = append(schemas, gatherComponentRequestBodies(spec.Components)...) + schemas = append(schemas, gatherComponentHeaders(spec.Components)...) + } + + // Gather client response wrapper types for operations that will generate + // client code. These synthetic entries exist so wrapper types like + // `CreateChatCompletionResponse` participate in collision detection. + if opts.Generate.Client { + schemas = append(schemas, gatherClientResponseWrappers(spec)...) + } + + return schemas +} + +func gatherComponentSchemas(components *openapi3.Components) []*GatheredSchema { + var result []*GatheredSchema + for _, name := range SortedSchemaKeys(components.Schemas) { + schemaRef := components.Schemas[name] + if schemaRef == nil || schemaRef.Value == nil { + continue + } + var goNameOverride string + if schemaRef.Ref == "" { + goNameOverride = extractGoNameOverride(schemaRef.Value.Extensions) + } + result = append(result, &GatheredSchema{ + Path: SchemaPath{"components", "schemas", name}, + Context: ContextComponentSchema, + Ref: schemaRef.Ref, + Schema: schemaRef.Value, + ComponentName: name, + GoNameOverride: goNameOverride, + }) + } + return result +} + +func gatherComponentParameters(components *openapi3.Components) []*GatheredSchema { + var result []*GatheredSchema + for _, name := range SortedMapKeys(components.Parameters) { + paramRef := components.Parameters[name] + if paramRef == nil || paramRef.Value == nil { + continue + } + param := paramRef.Value + if param.Schema != nil && param.Schema.Value != nil { + var goNameOverride string + if paramRef.Ref == "" { + goNameOverride = extractGoNameOverride(param.Extensions) + } + result = append(result, &GatheredSchema{ + Path: SchemaPath{"components", "parameters", name}, + Context: ContextComponentParameter, + Ref: paramRef.Ref, + Schema: param.Schema.Value, + ComponentName: name, + GoNameOverride: goNameOverride, + }) + } + } + return result +} + +func gatherComponentResponses(components *openapi3.Components) []*GatheredSchema { + var result []*GatheredSchema + for _, name := range SortedMapKeys(components.Responses) { + responseRef := components.Responses[name] + if responseRef == nil || responseRef.Value == nil { + continue + } + response := responseRef.Value + var goNameOverride string + if responseRef.Ref == "" { + goNameOverride = extractGoNameOverride(response.Extensions) + } + for _, mediaType := range SortedMapKeys(response.Content) { + if !util.IsMediaTypeJson(mediaType) { + continue + } + mt := response.Content[mediaType] + if mt.Schema != nil && mt.Schema.Value != nil { + result = append(result, &GatheredSchema{ + Path: SchemaPath{"components", "responses", name, "content", mediaType}, + Context: ContextComponentResponse, + Ref: responseRef.Ref, + Schema: mt.Schema.Value, + ContentType: mediaType, + ComponentName: name, + GoNameOverride: goNameOverride, + }) + } + } + } + return result +} + +func gatherComponentRequestBodies(components *openapi3.Components) []*GatheredSchema { + var result []*GatheredSchema + for _, name := range SortedMapKeys(components.RequestBodies) { + bodyRef := components.RequestBodies[name] + if bodyRef == nil || bodyRef.Value == nil { + continue + } + body := bodyRef.Value + var goNameOverride string + if bodyRef.Ref == "" { + goNameOverride = extractGoNameOverride(body.Extensions) + } + for _, mediaType := range SortedMapKeys(body.Content) { + if !util.IsMediaTypeJson(mediaType) { + continue + } + mt := body.Content[mediaType] + if mt.Schema != nil && mt.Schema.Value != nil { + result = append(result, &GatheredSchema{ + Path: SchemaPath{"components", "requestBodies", name, "content", mediaType}, + Context: ContextComponentRequestBody, + Ref: bodyRef.Ref, + Schema: mt.Schema.Value, + ContentType: mediaType, + ComponentName: name, + GoNameOverride: goNameOverride, + }) + } + } + } + return result +} + +func gatherComponentHeaders(components *openapi3.Components) []*GatheredSchema { + var result []*GatheredSchema + for _, name := range SortedMapKeys(components.Headers) { + headerRef := components.Headers[name] + if headerRef == nil || headerRef.Value == nil { + continue + } + header := headerRef.Value + if header.Schema != nil && header.Schema.Value != nil { + var goNameOverride string + if headerRef.Ref == "" { + goNameOverride = extractGoNameOverride(header.Extensions) + } + result = append(result, &GatheredSchema{ + Path: SchemaPath{"components", "headers", name}, + Context: ContextComponentHeader, + Ref: headerRef.Ref, + Schema: header.Schema.Value, + ComponentName: name, + GoNameOverride: goNameOverride, + }) + } + } + return result +} + +// gatherClientResponseWrappers creates synthetic schema entries for each +// operation that would generate a client response wrapper type like +// `Response`. These don't correspond to a real schema in the +// spec but they need names that don't collide with real types. +func gatherClientResponseWrappers(spec *openapi3.T) []*GatheredSchema { + var result []*GatheredSchema + + if spec.Paths == nil { + return result + } + + // Collect all operations sorted for determinism + type opEntry struct { + path string + method string + op *openapi3.Operation + } + var ops []opEntry + + pathKeys := SortedMapKeys(spec.Paths.Map()) + for _, path := range pathKeys { + pathItem := spec.Paths.Find(path) + if pathItem == nil { + continue + } + for method, op := range pathItem.Operations() { + if op != nil && op.OperationID != "" { + ops = append(ops, opEntry{path: path, method: method, op: op}) + } + } + } + + // Sort by operationID for determinism + sort.Slice(ops, func(i, j int) bool { + return ops[i].op.OperationID < ops[j].op.OperationID + }) + + for _, entry := range ops { + result = append(result, &GatheredSchema{ + Path: SchemaPath{"paths", entry.path, entry.method, "x-client-response-wrapper"}, + Context: ContextClientResponseWrapper, + OperationID: entry.op.OperationID, + }) + } + + return result +} + +// FormatPath returns a human-readable representation of the path for debugging. +func (gs *GatheredSchema) FormatPath() string { + return fmt.Sprintf("#/%s", strings.Join(gs.Path, "/")) +} + +// extractGoNameOverride reads the x-go-name extension from extensions and +// returns its value, or "" if not present or invalid. +func extractGoNameOverride(extensions map[string]any) string { + ext, ok := extensions[extGoName] + if !ok { + return "" + } + name, err := extTypeName(ext) + if err != nil { + return "" + } + return name +} diff --git a/pkg/codegen/gather_test.go b/pkg/codegen/gather_test.go new file mode 100644 index 0000000000..24e63b000b --- /dev/null +++ b/pkg/codegen/gather_test.go @@ -0,0 +1,356 @@ +package codegen + +import ( + "testing" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGatherSchemas_ComponentSchemas(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Schemas: openapi3.Schemas{ + "Pet": &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + "Owner": &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 2) + + // Sorted order: Owner, Pet + assert.Equal(t, SchemaPath{"components", "schemas", "Owner"}, schemas[0].Path) + assert.Equal(t, ContextComponentSchema, schemas[0].Context) + assert.Equal(t, "Owner", schemas[0].ComponentName) + + assert.Equal(t, SchemaPath{"components", "schemas", "Pet"}, schemas[1].Path) + assert.Equal(t, ContextComponentSchema, schemas[1].Context) + assert.Equal(t, "Pet", schemas[1].ComponentName) +} + +func TestGatherSchemas_ComponentParameters(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Parameters: openapi3.ParametersMap{ + "Limit": &openapi3.ParameterRef{ + Value: &openapi3.Parameter{ + Name: "limit", + In: "query", + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"integer"}}, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, SchemaPath{"components", "parameters", "Limit"}, schemas[0].Path) + assert.Equal(t, ContextComponentParameter, schemas[0].Context) + assert.Equal(t, "Limit", schemas[0].ComponentName) +} + +func TestGatherSchemas_ComponentResponses(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Responses: openapi3.ResponseBodies{ + "Error": &openapi3.ResponseRef{ + Value: &openapi3.Response{ + Content: openapi3.Content{ + "application/json": &openapi3.MediaType{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, SchemaPath{"components", "responses", "Error", "content", "application/json"}, schemas[0].Path) + assert.Equal(t, ContextComponentResponse, schemas[0].Context) + assert.Equal(t, "Error", schemas[0].ComponentName) + assert.Equal(t, "application/json", schemas[0].ContentType) +} + +func TestGatherSchemas_ComponentRequestBodies(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + RequestBodies: openapi3.RequestBodies{ + "CreatePet": &openapi3.RequestBodyRef{ + Value: &openapi3.RequestBody{ + Content: openapi3.Content{ + "application/json": &openapi3.MediaType{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, SchemaPath{"components", "requestBodies", "CreatePet", "content", "application/json"}, schemas[0].Path) + assert.Equal(t, ContextComponentRequestBody, schemas[0].Context) + assert.Equal(t, "CreatePet", schemas[0].ComponentName) +} + +func TestGatherSchemas_ComponentHeaders(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Headers: openapi3.Headers{ + "X-Rate-Limit": &openapi3.HeaderRef{ + Value: &openapi3.Header{ + Parameter: openapi3.Parameter{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"integer"}}, + }, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, SchemaPath{"components", "headers", "X-Rate-Limit"}, schemas[0].Path) + assert.Equal(t, ContextComponentHeader, schemas[0].Context) +} + +func TestGatherSchemas_ClientResponseWrappers(t *testing.T) { + paths := openapi3.NewPaths() + paths.Set("/pets", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "listPets", + }, + Post: &openapi3.Operation{ + OperationID: "createPet", + }, + }) + + spec := &openapi3.T{ + Paths: paths, + } + + // Without client generation, no wrappers + opts := Configuration{Generate: GenerateOptions{Client: false}} + schemas := GatherSchemas(spec, opts) + assert.Len(t, schemas, 0) + + // With client generation, wrappers are gathered + opts = Configuration{Generate: GenerateOptions{Client: true}} + schemas = GatherSchemas(spec, opts) + assert.Len(t, schemas, 2) + + // Check they're sorted by operationID + assert.Equal(t, ContextClientResponseWrapper, schemas[0].Context) + assert.Equal(t, "createPet", schemas[0].OperationID) + assert.Equal(t, ContextClientResponseWrapper, schemas[1].Context) + assert.Equal(t, "listPets", schemas[1].OperationID) +} + +func TestGatherSchemas_GoNameOverride_Schema(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Schemas: openapi3.Schemas{ + "Renamer": &openapi3.SchemaRef{ + Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Extensions: map[string]any{"x-go-name": "SpecialName"}, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, "SpecialName", schemas[0].GoNameOverride) +} + +func TestGatherSchemas_GoNameOverride_Response(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Responses: openapi3.ResponseBodies{ + "Outcome": &openapi3.ResponseRef{ + Value: &openapi3.Response{ + Extensions: map[string]any{"x-go-name": "OutcomeResult"}, + Content: openapi3.Content{ + "application/json": &openapi3.MediaType{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, "OutcomeResult", schemas[0].GoNameOverride) +} + +func TestGatherSchemas_GoNameOverride_RequestBody(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + RequestBodies: openapi3.RequestBodies{ + "Payload": &openapi3.RequestBodyRef{ + Value: &openapi3.RequestBody{ + Extensions: map[string]any{"x-go-name": "PayloadBody"}, + Content: openapi3.Content{ + "application/json": &openapi3.MediaType{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, "PayloadBody", schemas[0].GoNameOverride) +} + +func TestGatherSchemas_GoNameOverride_SkippedForRef(t *testing.T) { + spec := &openapi3.T{ + Components: &openapi3.Components{ + Schemas: openapi3.Schemas{ + "AliasedPet": &openapi3.SchemaRef{ + Ref: "#/components/schemas/Pet", + Value: &openapi3.Schema{ + Type: &openapi3.Types{"object"}, + Extensions: map[string]any{"x-go-name": "ShouldBeIgnored"}, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + require.Len(t, schemas, 1) + assert.Equal(t, "", schemas[0].GoNameOverride) +} + +func TestGatherSchemas_AllSections(t *testing.T) { + // Spec with "Bar" in schemas, parameters, responses, requestBodies, headers + // This is the issue #200 scenario (cross-section collision) + paths := openapi3.NewPaths() + spec := &openapi3.T{ + Paths: paths, + Components: &openapi3.Components{ + Schemas: openapi3.Schemas{ + "Bar": &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + Parameters: openapi3.ParametersMap{ + "Bar": &openapi3.ParameterRef{ + Value: &openapi3.Parameter{ + Name: "Bar", + In: "query", + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"string"}}, + }, + }, + }, + }, + Responses: openapi3.ResponseBodies{ + "Bar": &openapi3.ResponseRef{ + Value: &openapi3.Response{ + Content: openapi3.Content{ + "application/json": &openapi3.MediaType{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + }, + }, + }, + RequestBodies: openapi3.RequestBodies{ + "Bar": &openapi3.RequestBodyRef{ + Value: &openapi3.RequestBody{ + Content: openapi3.Content{ + "application/json": &openapi3.MediaType{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"object"}}, + }, + }, + }, + }, + }, + }, + Headers: openapi3.Headers{ + "Bar": &openapi3.HeaderRef{ + Value: &openapi3.Header{ + Parameter: openapi3.Parameter{ + Schema: &openapi3.SchemaRef{ + Value: &openapi3.Schema{Type: &openapi3.Types{"boolean"}}, + }, + }, + }, + }, + }, + }, + } + + opts := Configuration{} + schemas := GatherSchemas(spec, opts) + + // Should have 5 entries: schema, parameter, response, requestBody, header + assert.Len(t, schemas, 5) + + // Verify contexts are all different + contexts := make(map[SchemaContext]bool) + for _, s := range schemas { + contexts[s.Context] = true + } + assert.True(t, contexts[ContextComponentSchema]) + assert.True(t, contexts[ContextComponentParameter]) + assert.True(t, contexts[ContextComponentResponse]) + assert.True(t, contexts[ContextComponentRequestBody]) + assert.True(t, contexts[ContextComponentHeader]) +} diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go index eb6e3e1fd3..3ed611f392 100644 --- a/pkg/codegen/operations.go +++ b/pkg/codegen/operations.go @@ -342,7 +342,29 @@ 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 { - responseSchema, err := GenerateGoSchema(contentType.Schema, []string{o.OperationId, responseName}) + // 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) && true { // HACK + 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) } @@ -386,7 +408,11 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini return nil, fmt.Errorf("error dereferencing response Ref: %w", err) } if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) { - refType += mediaTypeToCamelCase(contentTypeName) + if resolved := resolvedNameForRefPath(responseRef.Ref, contentTypeName); resolved != "" { + refType = resolved + mediaTypeToCamelCase(contentTypeName) + } else { + refType += mediaTypeToCamelCase(contentTypeName) + } } td.Schema.RefType = refType } diff --git a/pkg/codegen/resolve_names.go b/pkg/codegen/resolve_names.go new file mode 100644 index 0000000000..f6d65f5b92 --- /dev/null +++ b/pkg/codegen/resolve_names.go @@ -0,0 +1,339 @@ +package codegen + +import ( + "fmt" + "sort" + "strconv" + "strings" +) + +// ResolvedName holds the final Go type name assigned to a gathered schema. +type ResolvedName struct { + Schema *GatheredSchema + GoName string // The resolved Go type name + Candidate string // The initial candidate name before collision resolution + Pinned bool // True if name came from x-go-name; must not be renamed +} + +// ResolveNames takes the gathered schemas and assigns unique Go type names to each. +// It returns a map from the schema's path string to the resolved Go type name. +func ResolveNames(schemas []*GatheredSchema) map[string]string { + // Step 1: Generate candidate names for all schemas + candidates := make([]*ResolvedName, len(schemas)) + for i, s := range schemas { + candidate := generateCandidateName(s) + candidates[i] = &ResolvedName{ + Schema: s, + GoName: candidate, + Candidate: candidate, + Pinned: s.GoNameOverride != "", + } + } + + // Step 2: Resolve collisions iteratively + resolveCollisions(candidates) + + // Step 3: Build the result map + result := make(map[string]string, len(candidates)) + for _, c := range candidates { + result[c.Schema.Path.String()] = c.GoName + } + return result +} + +// generateCandidateName produces an initial Go type name candidate based on +// the schema's location and context in the OpenAPI document. +func generateCandidateName(s *GatheredSchema) string { + if s.GoNameOverride != "" { + return s.GoNameOverride + } + + switch s.Context { + case ContextComponentSchema: + return SchemaNameToTypeName(s.ComponentName) + + case ContextComponentParameter: + return SchemaNameToTypeName(s.ComponentName) + + case ContextComponentResponse: + return SchemaNameToTypeName(s.ComponentName) + + case ContextComponentRequestBody: + return SchemaNameToTypeName(s.ComponentName) + + case ContextComponentHeader: + return SchemaNameToTypeName(s.ComponentName) + + case ContextClientResponseWrapper: + // Client response wrappers use: OperationId + responseTypeSuffix + return fmt.Sprintf("%s%s", SchemaNameToTypeName(s.OperationID), responseTypeSuffix) + + case ContextOperationParameter: + if s.OperationID != "" { + return SchemaNameToTypeName(s.OperationID) + "Parameter" + } + return SchemaNameToTypeName(s.ComponentName) + "Parameter" + + case ContextOperationRequestBody: + if s.OperationID != "" { + ct := contentTypeSuffix(s.ContentType) + return SchemaNameToTypeName(s.OperationID) + ct + "Request" + } + return SchemaNameToTypeName(s.ComponentName) + "Request" + + case ContextOperationResponse: + if s.OperationID != "" { + ct := contentTypeSuffix(s.ContentType) + return SchemaNameToTypeName(s.OperationID) + s.StatusCode + ct + "Response" + } + return SchemaNameToTypeName(s.ComponentName) + "Response" + + default: + return SchemaNameToTypeName(s.ComponentName) + } +} + +// resolveCollisions detects and resolves naming collisions among the resolved names. +// It applies strategies in global phases of increasing aggressiveness: +// 1. Context suffix (Schema, Parameter, Response, etc.) +// 2. Per-schema disambiguation (content type, status code, etc.) +// 3. Numeric fallback +// +// Each strategy is applied to ALL colliding groups, then collisions are +// re-checked globally before moving to the next strategy. This prevents +// oscillation between strategies (e.g., context suffix and content type +// suffix repeatedly appending to the same names without resolution). +func resolveCollisions(names []*ResolvedName) { + strategies := []func([]*ResolvedName) bool{ + strategyContextSuffix, + strategyPerSchemaDisambiguate, + strategyNumericFallback, + } + + const maxIterations = 20 + + for _, strategy := range strategies { + for iter := 0; iter < maxIterations; iter++ { + groups := groupByName(names) + anyCollision := false + anyProgress := false + for _, group := range groups { + if len(group) <= 1 { + continue + } + anyCollision = true + if strategy(group) { + anyProgress = true + } + } + if !anyCollision { + return + } + if !anyProgress { + break // This strategy can't help; try the next one + } + } + } +} + +// groupByName groups ResolvedNames by their current GoName. +func groupByName(names []*ResolvedName) map[string][]*ResolvedName { + groups := make(map[string][]*ResolvedName) + for _, n := range names { + groups[n.GoName] = append(groups[n.GoName], n) + } + return groups +} + +// strategyContextSuffix attempts to resolve collisions by appending a suffix +// derived from the schema's context (Schema, Parameter, Response, etc.). +// Component schemas are "privileged" — if exactly one member is a component +// schema, it keeps the bare name and only the others get suffixed. +// Returns true if any name was modified, false if no progress was made. +func strategyContextSuffix(group []*ResolvedName) bool { + // Count how many are component schemas (privileged) + var componentSchemaCount int + for _, n := range group { + if n.Schema.IsComponentSchema() { + componentSchemaCount++ + } + } + + progress := false + for _, n := range group { + if n.Pinned { + continue + } + + suffix := n.Schema.Context.Suffix() + if suffix == "" { + continue + } + + // If exactly one is a component schema, it keeps the bare name + if componentSchemaCount == 1 && n.Schema.IsComponentSchema() { + continue + } + + // Don't add suffix if name already ends with it + if strings.HasSuffix(n.GoName, suffix) { + continue + } + + n.GoName = n.GoName + suffix + progress = true + } + return progress +} + +// strategyPerSchemaDisambiguate tries several per-schema disambiguation strategies. +// Returns true if any name was modified, false if no progress was made. +func strategyPerSchemaDisambiguate(group []*ResolvedName) bool { + progress := tryContentTypeSuffix(group) + if !progress && tryStatusCodeSuffix(group) { + progress = true + } + if !progress && tryParamIndexSuffix(group) { + progress = true + } + return progress +} + +// tryContentTypeSuffix appends a content type discriminator when schemas +// differ by media type (e.g., JSON vs XML). +// Returns true if any name was modified, false if no progress was made. +func tryContentTypeSuffix(group []*ResolvedName) bool { + // Check if any members have different content types + contentTypes := make(map[string]bool) + for _, n := range group { + if n.Schema.ContentType != "" { + contentTypes[n.Schema.ContentType] = true + } + } + if len(contentTypes) <= 1 { + return false + } + + progress := false + for _, n := range group { + if n.Pinned { + continue + } + if n.Schema.ContentType == "" { + continue + } + suffix := contentTypeSuffix(n.Schema.ContentType) + if suffix != "" && !strings.HasSuffix(n.GoName, suffix) { + n.GoName = n.GoName + suffix + progress = true + } + } + return progress +} + +// tryStatusCodeSuffix appends the HTTP status code when schemas differ by status. +// Returns true if any name was modified, false if no progress was made. +func tryStatusCodeSuffix(group []*ResolvedName) bool { + statusCodes := make(map[string]bool) + for _, n := range group { + if n.Schema.StatusCode != "" { + statusCodes[n.Schema.StatusCode] = true + } + } + if len(statusCodes) <= 1 { + return false + } + + progress := false + for _, n := range group { + if n.Pinned { + continue + } + if n.Schema.StatusCode != "" && !strings.HasSuffix(n.GoName, n.Schema.StatusCode) { + n.GoName = n.GoName + n.Schema.StatusCode + progress = true + } + } + return progress +} + +// tryParamIndexSuffix appends a parameter index when schemas differ by position. +// Returns true if any name was modified, false if no progress was made. +func tryParamIndexSuffix(group []*ResolvedName) bool { + hasMultipleParams := false + for i := 0; i < len(group); i++ { + for j := i + 1; j < len(group); j++ { + if group[i].Schema.ParamIndex != group[j].Schema.ParamIndex { + hasMultipleParams = true + break + } + } + if hasMultipleParams { + break + } + } + if !hasMultipleParams { + return false + } + + progress := false + for _, n := range group { + if n.Pinned { + continue + } + suffix := strconv.Itoa(n.Schema.ParamIndex) + if !strings.HasSuffix(n.GoName, suffix) { + n.GoName = n.GoName + suffix + progress = true + } + } + return progress +} + +// strategyNumericFallback is the last resort: append increasing numbers. +// Returns true if any name was modified (always true when group has 2+ members). +func strategyNumericFallback(group []*ResolvedName) bool { + // Sort for determinism: pinned first, then component schemas, then by path + sort.Slice(group, func(i, j int) bool { + if group[i].Pinned != group[j].Pinned { + return group[i].Pinned + } + if group[i].Schema.IsComponentSchema() != group[j].Schema.IsComponentSchema() { + return group[i].Schema.IsComponentSchema() + } + return group[i].Schema.Path.String() < group[j].Schema.Path.String() + }) + + // First non-pinned keeps name, rest get numeric suffix + for i := 1; i < len(group); i++ { + if group[i].Pinned { + continue + } + group[i].GoName = group[i].GoName + strconv.Itoa(i+1) + } + return len(group) > 1 +} + +// contentTypeSuffix returns a short suffix for a media type. +func contentTypeSuffix(ct string) string { + if ct == "" { + return "" + } + ct = strings.ToLower(ct) + switch { + case strings.Contains(ct, "json"): + return "JSON" + case strings.Contains(ct, "xml"): + return "XML" + case strings.Contains(ct, "form"): + return "Form" + case strings.Contains(ct, "text"): + return "Text" + case strings.Contains(ct, "octet"): + return "Binary" + case strings.Contains(ct, "yaml"): + return "YAML" + default: + return mediaTypeToCamelCase(ct) + } +} diff --git a/pkg/codegen/resolve_names_test.go b/pkg/codegen/resolve_names_test.go new file mode 100644 index 0000000000..806eaf6740 --- /dev/null +++ b/pkg/codegen/resolve_names_test.go @@ -0,0 +1,379 @@ +package codegen + +import ( + "testing" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/assert" +) + +func TestResolveNames_NoCollisions(t *testing.T) { + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Pet"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Pet", + }, + { + Path: SchemaPath{"components", "schemas", "Owner"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Owner", + }, + } + + result := ResolveNames(schemas) + + assert.Equal(t, "Pet", result["components/schemas/Pet"]) + assert.Equal(t, "Owner", result["components/schemas/Owner"]) +} + +func TestResolveNames_Issue200_CrossSectionCollisions(t *testing.T) { + // "Bar" appears in schemas, parameters, responses, requestBodies, headers + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Bar"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Bar", + }, + { + Path: SchemaPath{"components", "parameters", "Bar"}, + Context: ContextComponentParameter, + Schema: &openapi3.Schema{}, + ComponentName: "Bar", + }, + { + Path: SchemaPath{"components", "responses", "Bar", "content", "application/json"}, + Context: ContextComponentResponse, + Schema: &openapi3.Schema{}, + ComponentName: "Bar", + ContentType: "application/json", + }, + { + Path: SchemaPath{"components", "requestBodies", "Bar", "content", "application/json"}, + Context: ContextComponentRequestBody, + Schema: &openapi3.Schema{}, + ComponentName: "Bar", + ContentType: "application/json", + }, + { + Path: SchemaPath{"components", "headers", "Bar"}, + Context: ContextComponentHeader, + Schema: &openapi3.Schema{}, + ComponentName: "Bar", + }, + } + + result := ResolveNames(schemas) + + // Component schema is privileged — keeps bare name + assert.Equal(t, "Bar", result["components/schemas/Bar"]) + // Others get context suffixes + assert.Equal(t, "BarParameter", result["components/parameters/Bar"]) + assert.Equal(t, "BarResponse", result["components/responses/Bar/content/application/json"]) + assert.Equal(t, "BarRequestBody", result["components/requestBodies/Bar/content/application/json"]) + assert.Equal(t, "BarHeader", result["components/headers/Bar"]) +} + +func TestResolveNames_Issue1474_ClientWrapperCollision(t *testing.T) { + // Schema named "CreateChatCompletionResponse" collides with + // client wrapper for operation "createChatCompletion" which + // would generate "CreateChatCompletionResponse". + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "CreateChatCompletionResponse"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "CreateChatCompletionResponse", + }, + { + Path: SchemaPath{"paths", "/chat/completions", "POST", "x-client-response-wrapper"}, + Context: ContextClientResponseWrapper, + OperationID: "createChatCompletion", + }, + } + + result := ResolveNames(schemas) + + // Component schema is privileged — keeps its name + assert.Equal(t, "CreateChatCompletionResponse", result["components/schemas/CreateChatCompletionResponse"]) + // Client wrapper gets a suffix to avoid collision + wrapperName := result["paths//chat/completions/POST/x-client-response-wrapper"] + assert.NotEqual(t, "CreateChatCompletionResponse", wrapperName, + "client wrapper should not collide with component schema") + assert.Contains(t, wrapperName, "Response", + "client wrapper should still contain 'Response'") +} + +func TestResolveNames_PrivilegedComponentSchema(t *testing.T) { + // When exactly one collision member is a component schema, + // it keeps the bare name + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Foo"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + }, + { + Path: SchemaPath{"components", "parameters", "Foo"}, + Context: ContextComponentParameter, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + }, + } + + result := ResolveNames(schemas) + + assert.Equal(t, "Foo", result["components/schemas/Foo"]) + assert.Equal(t, "FooParameter", result["components/parameters/Foo"]) +} + +func TestResolveNames_NoComponentSchema_AllGetSuffixes(t *testing.T) { + // When no member is a component schema, all get suffixed + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "parameters", "Foo"}, + Context: ContextComponentParameter, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + }, + { + Path: SchemaPath{"components", "responses", "Foo", "content", "application/json"}, + Context: ContextComponentResponse, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + ContentType: "application/json", + }, + } + + result := ResolveNames(schemas) + + assert.Equal(t, "FooParameter", result["components/parameters/Foo"]) + assert.Equal(t, "FooResponse", result["components/responses/Foo/content/application/json"]) +} + +func TestResolveNames_NumericFallback(t *testing.T) { + // Two schemas with same context that can't be disambiguated + // by context suffix (both are component schemas) + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Foo"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + }, + { + // Hypothetical: same candidate name from a different path + // This shouldn't normally happen with real specs, but tests the fallback + Path: SchemaPath{"components", "schemas", "foo"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "foo", + }, + } + + result := ResolveNames(schemas) + + names := make(map[string]bool) + for _, name := range result { + names[name] = true + } + // Both should have unique names + assert.Len(t, names, 2, "should have two unique names") +} + +func TestResolveNames_MultipleJsonContentTypes(t *testing.T) { + // "Order" appears in schemas and requestBodies. The requestBody has + // 3 content types that all contain "json" and map to the same "JSON" + // suffix. The global phase approach should prevent oscillation between + // context suffix and content type suffix, letting numeric fallback resolve. + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Order"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Order", + }, + { + Path: SchemaPath{"components", "requestBodies", "Order", "content", "application/json"}, + Context: ContextComponentRequestBody, + Schema: &openapi3.Schema{}, + ComponentName: "Order", + ContentType: "application/json", + }, + { + Path: SchemaPath{"components", "requestBodies", "Order", "content", "application/merge-patch+json"}, + Context: ContextComponentRequestBody, + Schema: &openapi3.Schema{}, + ComponentName: "Order", + ContentType: "application/merge-patch+json", + }, + { + Path: SchemaPath{"components", "requestBodies", "Order", "content", "application/json-patch+json"}, + Context: ContextComponentRequestBody, + Schema: &openapi3.Schema{}, + ComponentName: "Order", + ContentType: "application/json-patch+json", + }, + } + + result := ResolveNames(schemas) + + // Component schema keeps bare name + assert.Equal(t, "Order", result["components/schemas/Order"]) + + // All 3 requestBody types must have unique names + names := make(map[string]bool) + for _, name := range result { + names[name] = true + } + assert.Len(t, names, 4, "all 4 types should have unique names") + + // The first requestBody should get RequestBody+JSON suffixes + assert.Equal(t, "OrderRequestBodyJSON", + result["components/requestBodies/Order/content/application/json"]) + + // The remaining two collide on OrderRequestBodyJSON and get numeric fallback + jsonPatchName := result["components/requestBodies/Order/content/application/json-patch+json"] + mergePatchName := result["components/requestBodies/Order/content/application/merge-patch+json"] + assert.NotEqual(t, jsonPatchName, mergePatchName, + "json-patch and merge-patch types must have different names") + assert.Contains(t, jsonPatchName, "OrderRequestBodyJSON") + assert.Contains(t, mergePatchName, "OrderRequestBodyJSON") +} + +func TestResolveNames_XGoNamePinned_Schema(t *testing.T) { + // Pattern K: schema "Renamer" has x-go-name="SpecialName" which collides + // with nothing, but a response also named "Renamer" should keep its + // normal resolved name. The schema is pinned. + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Renamer"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Renamer", + GoNameOverride: "SpecialName", + }, + { + Path: SchemaPath{"components", "responses", "Renamer", "content", "application/json"}, + Context: ContextComponentResponse, + Schema: &openapi3.Schema{}, + ComponentName: "Renamer", + ContentType: "application/json", + }, + } + + result := ResolveNames(schemas) + + // Schema pinned to SpecialName + assert.Equal(t, "SpecialName", result["components/schemas/Renamer"]) + // Response keeps bare name since there's no collision with "Renamer" + assert.Equal(t, "Renamer", result["components/responses/Renamer/content/application/json"]) +} + +func TestResolveNames_XGoNamePinned_Response(t *testing.T) { + // Pattern L: response "Outcome" has x-go-name="OutcomeResult" and + // schema also named "Outcome". The response is pinned as "OutcomeResult", + // so the schema keeps "Outcome" (no collision). + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Outcome"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Outcome", + }, + { + Path: SchemaPath{"components", "responses", "Outcome", "content", "application/json"}, + Context: ContextComponentResponse, + Schema: &openapi3.Schema{}, + ComponentName: "Outcome", + ContentType: "application/json", + GoNameOverride: "OutcomeResult", + }, + } + + result := ResolveNames(schemas) + + // Schema keeps bare name + assert.Equal(t, "Outcome", result["components/schemas/Outcome"]) + // Response pinned to OutcomeResult + assert.Equal(t, "OutcomeResult", result["components/responses/Outcome/content/application/json"]) +} + +func TestResolveNames_XGoNamePinned_RequestBody(t *testing.T) { + // Pattern M: requestBody "Payload" has x-go-name="PayloadBody" and + // schema also named "Payload". The requestBody is pinned. + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Payload"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Payload", + }, + { + Path: SchemaPath{"components", "requestBodies", "Payload", "content", "application/json"}, + Context: ContextComponentRequestBody, + Schema: &openapi3.Schema{}, + ComponentName: "Payload", + ContentType: "application/json", + GoNameOverride: "PayloadBody", + }, + } + + result := ResolveNames(schemas) + + // Schema keeps bare name + assert.Equal(t, "Payload", result["components/schemas/Payload"]) + // RequestBody pinned to PayloadBody + assert.Equal(t, "PayloadBody", result["components/requestBodies/Payload/content/application/json"]) +} + +func TestResolveNames_PinnedNotModifiedByStrategies(t *testing.T) { + // Pinned name "Foo" vs non-pinned parameter "Foo" → parameter gets suffixed + schemas := []*GatheredSchema{ + { + Path: SchemaPath{"components", "schemas", "Foo"}, + Context: ContextComponentSchema, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + GoNameOverride: "Foo", + }, + { + Path: SchemaPath{"components", "parameters", "Foo"}, + Context: ContextComponentParameter, + Schema: &openapi3.Schema{}, + ComponentName: "Foo", + }, + } + + result := ResolveNames(schemas) + + // Pinned schema stays as "Foo" + assert.Equal(t, "Foo", result["components/schemas/Foo"]) + // Parameter gets suffixed to resolve collision + assert.Equal(t, "FooParameter", result["components/parameters/Foo"]) +} + +func TestContentTypeSuffix(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"application/json", "JSON"}, + {"application/xml", "XML"}, + {"application/x-www-form-urlencoded", "Form"}, + {"text/plain", "Text"}, + {"application/octet-stream", "Binary"}, + {"application/yaml", "YAML"}, + {"", ""}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + assert.Equal(t, tt.expected, contentTypeSuffix(tt.input)) + }) + } +} diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 067d03955d..ff72d23b6b 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -40,21 +40,8 @@ type Schema struct { // The original OpenAPIv3 Schema. OAPISchema *openapi3.Schema - DefinedComp ComponentType // Indicates which component section defined this type } -// ComponentType is used to keep track of where a given schema came from, in order -// to perform type name collision resolution. -type ComponentType int - -const ( - ComponentTypeSchema = iota - ComponentTypeParameter - ComponentTypeRequestBody - ComponentTypeResponse - ComponentTypeHeader -) - func (s Schema) IsRef() bool { return s.RefType != "" } @@ -325,7 +312,6 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) { Description: schema.Description, OAPISchema: schema, SkipOptionalPointer: skipOptionalPointer, - DefinedComp: ComponentTypeSchema, } // AllOf is interesting, and useful. It's the union of a number of other @@ -835,9 +821,7 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { // We can process the schema through the generic schema processor if param.Schema != nil { - schema, err := GenerateGoSchema(param.Schema, path) - schema.DefinedComp = ComponentTypeParameter - return schema, err + return GenerateGoSchema(param.Schema, path) } // At this point, we have a content type. We know how to deal with @@ -847,7 +831,6 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { return Schema{ GoType: "string", Description: StringToGoComment(param.Description), - DefinedComp: ComponentTypeParameter, }, nil } @@ -858,14 +841,11 @@ func paramToGoType(param *openapi3.Parameter, path []string) (Schema, error) { return Schema{ GoType: "string", Description: StringToGoComment(param.Description), - DefinedComp: ComponentTypeParameter, }, nil } // For json, we go through the standard schema mechanism - schema, err := GenerateGoSchema(mt.Schema, path) - schema.DefinedComp = ComponentTypeParameter - return schema, err + return GenerateGoSchema(mt.Schema, path) } func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminator *openapi3.Discriminator, path []string) error { diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index 64caf12828..e4d932116a 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -259,8 +259,13 @@ func buildUnmarshalCaseStrict(typeDefinition ResponseTypeDefinition, caseAction return caseKey, caseClause } -// genResponseTypeName creates the name of generated response types (given the operationID): +// genResponseTypeName creates the name of generated response types (given the operationID). +// It first checks if the multi-pass name resolver has assigned a name for this +// wrapper type (which would happen if the default name collides with a schema type). func genResponseTypeName(operationID string) string { + if name, ok := globalState.resolvedClientWrapperNames[operationID]; ok { + return name + } return fmt.Sprintf("%s%s", UppercaseFirstCharacter(operationID), responseTypeSuffix) } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 549d5cffa3..adfeb7c89f 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -474,6 +474,20 @@ func refPathToGoTypeSelf(refPath string, local bool) (string, error) { return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local) } + // When multi-pass name resolution is active, the resolved name takes + // precedence over the spec-given name. For a $ref like + // #/components/schemas/Thing, we pass the section ("schemas") and + // name ("Thing") to resolvedNameForComponent, which looks up the + // final Go type name assigned by the collision resolver. + // Note: the resolver prioritizes component schemas — if a schema and + // a response both claim "Thing", the component schema keeps the original + // name and the response becomes "ThingResponse". + if depth == 4 && pathParts[0] == "#" && pathParts[1] == "components" { + if resolved := resolvedNameForComponent(pathParts[2], pathParts[3]); resolved != "" { + return resolved, nil + } + } + // Schemas may have been renamed locally, so look up the actual name in // the spec. name, err := findSchemaNameByRefPath(refPath, globalState.spec) @@ -1124,86 +1138,3 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool { func sliceContains[E comparable](s []E, v E) bool { return slices.Contains(s, v) } - -// FixDuplicateTypeNames renames duplicate type names. -func FixDuplicateTypeNames(typeDefs []TypeDefinition) []TypeDefinition { - if !hasDuplicatedTypeNames(typeDefs) { - return typeDefs - } - - // try to fix duplicate type names with their definition section - typeDefs = fixDuplicateTypeNamesWithCompName(typeDefs) - if !hasDuplicatedTypeNames(typeDefs) { - return typeDefs - } - - const maxIter = 100 - for i := 0; i < maxIter && hasDuplicatedTypeNames(typeDefs); i++ { - typeDefs = fixDuplicateTypeNamesDupCounts(typeDefs) - } - - if hasDuplicatedTypeNames(typeDefs) { - panic("too much duplicate type names") - } - - return typeDefs -} - -func hasDuplicatedTypeNames(typeDefs []TypeDefinition) bool { - dupCheck := make(map[string]int, len(typeDefs)) - - for _, d := range typeDefs { - dupCheck[d.TypeName]++ - - if dupCheck[d.TypeName] != 1 { - return true - } - } - - return false -} - -func fixDuplicateTypeNamesWithCompName(typeDefs []TypeDefinition) []TypeDefinition { - dupCheck := make(map[string]int, len(typeDefs)) - deDup := make([]TypeDefinition, len(typeDefs)) - - for i, d := range typeDefs { - dupCheck[d.TypeName]++ - - if dupCheck[d.TypeName] != 1 { - switch d.Schema.DefinedComp { - case ComponentTypeSchema: - d.TypeName += "Schema" - case ComponentTypeParameter: - d.TypeName += "Parameter" - case ComponentTypeRequestBody: - d.TypeName += "RequestBody" - case ComponentTypeResponse: - d.TypeName += "Response" - case ComponentTypeHeader: - d.TypeName += "Header" - } - } - - deDup[i] = d - } - - return deDup -} - -func fixDuplicateTypeNamesDupCounts(typeDefs []TypeDefinition) []TypeDefinition { - dupCheck := make(map[string]int, len(typeDefs)) - deDup := make([]TypeDefinition, len(typeDefs)) - - for i, d := range typeDefs { - dupCheck[d.TypeName]++ - - if dupCheck[d.TypeName] != 1 { - d.TypeName = d.TypeName + strconv.Itoa(dupCheck[d.TypeName]) - } - - deDup[i] = d - } - - return deDup -}