From 6c7ac1411c46b926a13c19160e83b28472e2051b Mon Sep 17 00:00:00 2001 From: bytethm Date: Tue, 19 Aug 2025 10:51:55 +0800 Subject: [PATCH 1/2] feat: add compatibility layer for different kin-openapi versions --- mcp_tools.go | 38 ++++++---------- openapi_compat.go | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 openapi_compat.go diff --git a/mcp_tools.go b/mcp_tools.go index 6804a4a..80ddcd0 100644 --- a/mcp_tools.go +++ b/mcp_tools.go @@ -112,11 +112,8 @@ func NewTool( ) *Tool { tool := &Tool{ Name: name, - InputSchema: &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeObject}, - Properties: make(openapi3.Schemas), - Required: []string{}, - }, + // Original: InputSchema: &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeObject}, Properties: make(openapi3.Schemas), Required: []string{}} + InputSchema: compat.CreateObjectSchemaCompat(), } for _, opt := range opts { @@ -136,9 +133,8 @@ func WithDescription(description string) ToolOption { // WithString adds a string parameter to the tool's input schema func WithString(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { - schema := &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeString}, - } + // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeString}} + schema := compat.CreateStringSchemaCompat() for _, opt := range opts { opt(schema) } @@ -152,9 +148,8 @@ func WithString(name string, opts ...PropertyOption) ToolOption { // WithNumber adds a number parameter to the tool's input schema func WithNumber(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { - schema := &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeNumber}, - } + // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeNumber}} + schema := compat.CreateNumberSchemaCompat() for _, opt := range opts { opt(schema) } @@ -168,9 +163,8 @@ func WithNumber(name string, opts ...PropertyOption) ToolOption { // WithInteger adds an integer parameter to the tool's input schema func WithInteger(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { - schema := &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeInteger}, - } + // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeInteger}} + schema := compat.CreateIntegerSchemaCompat() for _, opt := range opts { opt(schema) } @@ -184,9 +178,8 @@ func WithInteger(name string, opts ...PropertyOption) ToolOption { // WithBoolean adds a boolean parameter to the tool's input schema func WithBoolean(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { - schema := &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeBoolean}, - } + // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeBoolean}} + schema := compat.CreateBooleanSchemaCompat() for _, opt := range opts { opt(schema) } @@ -200,10 +193,8 @@ func WithBoolean(name string, opts ...PropertyOption) ToolOption { // WithObject adds an object parameter to the tool's input schema. func WithObject(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { - schema := &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeObject}, - Properties: make(openapi3.Schemas), - } + // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeObject}, Properties: make(openapi3.Schemas)} + schema := compat.CreateObjectSchemaCompat() for _, opt := range opts { opt(schema) } @@ -263,9 +254,8 @@ func Properties(props openapi3.Schemas) PropertyOption { // WithArray adds an array to the tool's input schema. func WithArray(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { - schema := &openapi3.Schema{ - Type: &openapi3.Types{openapi3.TypeArray}, - } + // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeArray}} + schema := compat.CreateArraySchemaCompat() for _, opt := range opts { opt(schema) } diff --git a/openapi_compat.go b/openapi_compat.go new file mode 100644 index 0000000..a7eacff --- /dev/null +++ b/openapi_compat.go @@ -0,0 +1,107 @@ +package mcp + +import ( + "reflect" + "sync" + + "github.com/getkin/kin-openapi/openapi3" +) + +// OpenAPICompat provides version compatibility for kin-openapi +// It handles the breaking change in v0.124.0 where Schema.Type changed from string to *Types +type OpenAPICompat struct { + // Cache the type information to avoid repeated reflection + once sync.Once + typeFieldType reflect.Type + isPointerType bool + typesSliceType reflect.Type +} + +// Global instance for convenience +var compat = &OpenAPICompat{} + +// initTypeInfo performs one-time reflection to determine the API version +func (c *OpenAPICompat) initTypeInfo() { + c.once.Do(func() { + schema := &openapi3.Schema{} + v := reflect.ValueOf(schema).Elem() + typeField := v.FieldByName("Type") + + if typeField.IsValid() { + c.typeFieldType = typeField.Type() + c.isPointerType = c.typeFieldType.Kind() == reflect.Ptr + + if c.isPointerType { + // v0.124.0+: Type is *Types where Types is []string + c.typesSliceType = c.typeFieldType.Elem() + } + } + }) +} + +// SetSchemaTypeCompat sets the Type field of a schema in a version-compatible way +func (c *OpenAPICompat) SetSchemaTypeCompat(schema *openapi3.Schema, typeName string) { + if schema == nil { + return + } + + // Initialize type info once + c.initTypeInfo() + + v := reflect.ValueOf(schema).Elem() + typeField := v.FieldByName("Type") + + if !typeField.IsValid() || !typeField.CanSet() { + return + } + + if c.isPointerType { + // v0.124.0+: Type is *Types ([]string) + typesValue := reflect.New(c.typesSliceType) + typesSlice := reflect.MakeSlice(c.typesSliceType, 1, 1) + typesSlice.Index(0).SetString(typeName) + typesValue.Elem().Set(typesSlice) + typeField.Set(typesValue) + } else { + // v0.123.0-: Type is string + typeField.SetString(typeName) + } +} + +// CreateSchemaCompat creates a new schema with proper Type field +func (c *OpenAPICompat) CreateSchemaCompat(typeName string) *openapi3.Schema { + schema := &openapi3.Schema{} + c.SetSchemaTypeCompat(schema, typeName) + return schema +} + +// CreateObjectSchemaCompat creates a new object schema with properties +func (c *OpenAPICompat) CreateObjectSchemaCompat() *openapi3.Schema { + schema := &openapi3.Schema{ + Properties: make(openapi3.Schemas), + Required: []string{}, + } + c.SetSchemaTypeCompat(schema, openapi3.TypeObject) + return schema +} + +// Convenience functions for common types +func (c *OpenAPICompat) CreateStringSchemaCompat() *openapi3.Schema { + return c.CreateSchemaCompat(openapi3.TypeString) +} + +func (c *OpenAPICompat) CreateNumberSchemaCompat() *openapi3.Schema { + return c.CreateSchemaCompat(openapi3.TypeNumber) +} + +func (c *OpenAPICompat) CreateIntegerSchemaCompat() *openapi3.Schema { + return c.CreateSchemaCompat(openapi3.TypeInteger) +} + +func (c *OpenAPICompat) CreateBooleanSchemaCompat() *openapi3.Schema { + return c.CreateSchemaCompat(openapi3.TypeBoolean) +} + +func (c *OpenAPICompat) CreateArraySchemaCompat() *openapi3.Schema { + return c.CreateSchemaCompat(openapi3.TypeArray) +} From 3bf780ca99354d52092fa63699ae88ced90433d6 Mon Sep 17 00:00:00 2001 From: bytethm Date: Tue, 19 Aug 2025 15:49:37 +0800 Subject: [PATCH 2/2] update --- internal/openapi/compat.go | 205 +++++++++++++++++++++++++++++++++++++ mcp_tools.go | 15 +-- mcp_tools_test.go | 91 ++++++++++++++++ openapi_compat.go | 107 ------------------- 4 files changed, 304 insertions(+), 114 deletions(-) create mode 100644 internal/openapi/compat.go delete mode 100644 openapi_compat.go diff --git a/internal/openapi/compat.go b/internal/openapi/compat.go new file mode 100644 index 0000000..16cdd99 --- /dev/null +++ b/internal/openapi/compat.go @@ -0,0 +1,205 @@ +package openapi + +import ( + "fmt" + "reflect" + "sync" + + "github.com/getkin/kin-openapi/openapi3" + "trpc.group/trpc-go/trpc-mcp-go/internal/log" +) + +// Compat provides version compatibility for kin-openapi +// It handles the breaking change in v0.124.0 where Schema.Type changed from string to *Types +type Compat struct { + // Cache the type information to avoid repeated reflection + once sync.Once + typeFieldType reflect.Type + isPointerType bool + typesSliceType reflect.Type + initError error // Track initialization errors +} + +// Global instances for convenience +var ( + DefaultCompat = &Compat{} + logger = log.NewZapLogger() +) + +// OpenAPI Compatibility Layer Error Handling: +// +// This compatibility layer handles kin-openapi version differences automatically. +// If you see ERROR logs mentioning "OpenAPI compatibility", it means: +// +// 1. There's a version mismatch between kin-openapi versions used by different libraries +// 2. The automatic compatibility failed - this usually requires framework developer attention +// 3. You should report this issue with the error message to the trpc-mcp-go maintainers +// +// Common causes: +// - Using an unsupported kin-openapi version (< v0.118.0 or > v0.132.0) +// - Conflicting dependencies pulling incompatible versions +// - Breaking changes in kin-openapi that we haven't adapted to yet + +// initTypeInfo performs one-time reflection to determine the API version +func (c *Compat) initTypeInfo() { + c.once.Do(func() { + defer func() { + if r := recover(); r != nil { + c.initError = fmt.Errorf("openapi compatibility init panic: %v", r) + logger.Errorf("OpenAPI compatibility FAILED - please report this issue: %v", c.initError) + } + }() + + schema := &openapi3.Schema{} + + // Validate input + if schema == nil { + c.initError = fmt.Errorf("schema is nil") + return + } + + v := reflect.ValueOf(schema) + if v.Kind() != reflect.Ptr || v.IsNil() { + c.initError = fmt.Errorf("schema must be a non-nil pointer") + return + } + + elem := v.Elem() + typeField := elem.FieldByName("Type") + + if !typeField.IsValid() { + c.initError = fmt.Errorf("Type field not found in openapi3.Schema") + logger.Errorf("OpenAPI compatibility FAILED: incompatible kin-openapi version detected - Schema.Type field missing") + return + } + + c.typeFieldType = typeField.Type() + c.isPointerType = c.typeFieldType.Kind() == reflect.Ptr + + if c.isPointerType { + // v0.124.0+: Type is *Types where Types is []string + elemType := c.typeFieldType.Elem() + if elemType.Kind() != reflect.Slice { + c.initError = fmt.Errorf("expected *[]string for Type field, got %v", c.typeFieldType) + logger.Errorf("OpenAPI compatibility FAILED: unexpected kin-openapi API structure change - Type field is %v, expected *[]string", c.typeFieldType) + return + } + c.typesSliceType = elemType + } + + // Initialization successful - no logging needed for normal operation + }) +} + +// SetSchemaTypeCompat sets the Type field of a schema in a version-compatible way +func (c *Compat) SetSchemaType(schema *openapi3.Schema, typeName string) { + // Input validation - silent return for user errors (these are not our bugs) + if schema == nil { + return + } + + if typeName == "" { + return + } + + // Initialize type info once + c.initTypeInfo() + + // Check for initialization errors + if c.initError != nil { + logger.Errorf("OpenAPI compatibility FAILED: %v", c.initError) + return + } + + // Safe reflection with panic recovery + defer func() { + if r := recover(); r != nil { + logger.Errorf("OpenAPI compatibility PANIC: %v - this indicates a serious compatibility issue", r) + } + }() + + v := reflect.ValueOf(schema) + if v.Kind() != reflect.Ptr || v.IsNil() { + // Silent return - this is a user error, not our bug + return + } + + elem := v.Elem() + typeField := elem.FieldByName("Type") + + if !typeField.IsValid() { + // Silent return - already logged during initialization + return + } + + if !typeField.CanSet() { + // Silent return - reflection constraint, not our bug + return + } + + if c.isPointerType { + // v0.124.0+: Type is *Types ([]string) + if c.typesSliceType.Kind() == reflect.Invalid { + // Silent return - already logged during initialization + return + } + + typesValue := reflect.New(c.typesSliceType) + typesSlice := reflect.MakeSlice(c.typesSliceType, 1, 1) + + // Validate slice element type + if typesSlice.Index(0).Kind() != reflect.String { + // Silent return - this would be an internal error already caught in init + return + } + + typesSlice.Index(0).SetString(typeName) + typesValue.Elem().Set(typesSlice) + typeField.Set(typesValue) + } else { + // v0.123.0-: Type is string + if typeField.Kind() != reflect.String { + // Silent return - this would be an internal error already caught in init + return + } + typeField.SetString(typeName) + } +} + +// CreateSchemaCompat creates a new schema with proper Type field +func (c *Compat) CreateSchema(typeName string) *openapi3.Schema { + schema := &openapi3.Schema{} + c.SetSchemaType(schema, typeName) + return schema +} + +// CreateObjectSchema creates a new object schema with properties +func (c *Compat) CreateObjectSchema() *openapi3.Schema { + schema := &openapi3.Schema{ + Properties: make(openapi3.Schemas), + Required: []string{}, + } + c.SetSchemaType(schema, openapi3.TypeObject) + return schema +} + +// Convenience functions for common types +func (c *Compat) CreateStringSchema() *openapi3.Schema { + return c.CreateSchema(openapi3.TypeString) +} + +func (c *Compat) CreateNumberSchema() *openapi3.Schema { + return c.CreateSchema(openapi3.TypeNumber) +} + +func (c *Compat) CreateIntegerSchema() *openapi3.Schema { + return c.CreateSchema(openapi3.TypeInteger) +} + +func (c *Compat) CreateBooleanSchema() *openapi3.Schema { + return c.CreateSchema(openapi3.TypeBoolean) +} + +func (c *Compat) CreateArraySchema() *openapi3.Schema { + return c.CreateSchema(openapi3.TypeArray) +} diff --git a/mcp_tools.go b/mcp_tools.go index 80ddcd0..f755f15 100644 --- a/mcp_tools.go +++ b/mcp_tools.go @@ -12,6 +12,7 @@ import ( "fmt" "github.com/getkin/kin-openapi/openapi3" + "trpc.group/trpc-go/trpc-mcp-go/internal/openapi" ) // ListToolsRequest represents a request to list available tools @@ -113,7 +114,7 @@ func NewTool( tool := &Tool{ Name: name, // Original: InputSchema: &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeObject}, Properties: make(openapi3.Schemas), Required: []string{}} - InputSchema: compat.CreateObjectSchemaCompat(), + InputSchema: openapi.DefaultCompat.CreateObjectSchema(), } for _, opt := range opts { @@ -134,7 +135,7 @@ func WithDescription(description string) ToolOption { func WithString(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeString}} - schema := compat.CreateStringSchemaCompat() + schema := openapi.DefaultCompat.CreateStringSchema() for _, opt := range opts { opt(schema) } @@ -149,7 +150,7 @@ func WithString(name string, opts ...PropertyOption) ToolOption { func WithNumber(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeNumber}} - schema := compat.CreateNumberSchemaCompat() + schema := openapi.DefaultCompat.CreateNumberSchema() for _, opt := range opts { opt(schema) } @@ -164,7 +165,7 @@ func WithNumber(name string, opts ...PropertyOption) ToolOption { func WithInteger(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeInteger}} - schema := compat.CreateIntegerSchemaCompat() + schema := openapi.DefaultCompat.CreateIntegerSchema() for _, opt := range opts { opt(schema) } @@ -179,7 +180,7 @@ func WithInteger(name string, opts ...PropertyOption) ToolOption { func WithBoolean(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeBoolean}} - schema := compat.CreateBooleanSchemaCompat() + schema := openapi.DefaultCompat.CreateBooleanSchema() for _, opt := range opts { opt(schema) } @@ -194,7 +195,7 @@ func WithBoolean(name string, opts ...PropertyOption) ToolOption { func WithObject(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeObject}, Properties: make(openapi3.Schemas)} - schema := compat.CreateObjectSchemaCompat() + schema := openapi.DefaultCompat.CreateObjectSchema() for _, opt := range opts { opt(schema) } @@ -255,7 +256,7 @@ func Properties(props openapi3.Schemas) PropertyOption { func WithArray(name string, opts ...PropertyOption) ToolOption { return func(t *Tool) { // Original: schema := &openapi3.Schema{Type: &openapi3.Types{openapi3.TypeArray}} - schema := compat.CreateArraySchemaCompat() + schema := openapi.DefaultCompat.CreateArraySchema() for _, opt := range opts { opt(schema) } diff --git a/mcp_tools_test.go b/mcp_tools_test.go index 705312f..434ed5f 100644 --- a/mcp_tools_test.go +++ b/mcp_tools_test.go @@ -10,7 +10,9 @@ import ( "context" "testing" + "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/assert" + "trpc.group/trpc-go/trpc-mcp-go/internal/openapi" ) // MockTool is a mock tool implementation for testing @@ -176,3 +178,92 @@ func TestMockTool(t *testing.T) { assert.NoError(t, err) assert.Equal(t, customResult, result) } + +// TestCompatibilityLayerWithCurrentVersion verifies that our compatibility layer +// produces the same results as the original code for current users +func TestCompatibilityLayerWithCurrentVersion(t *testing.T) { + // This test verifies that existing users (using kin-openapi v0.132.0) + // get exactly the same behavior as before + + // Test NewTool compatibility + t.Run("NewTool compatibility", func(t *testing.T) { + tool := NewTool("test-tool") + + // Verify the schema was created correctly + assert.NotNil(t, tool.InputSchema) + assert.NotNil(t, tool.InputSchema.Properties) + assert.Equal(t, []string{}, tool.InputSchema.Required) + + // For v0.132.0, Type should be *openapi3.Types + assert.NotNil(t, tool.InputSchema.Type) + assert.IsType(t, &openapi3.Types{}, tool.InputSchema.Type) + assert.Equal(t, openapi3.Types{openapi3.TypeObject}, *tool.InputSchema.Type) + }) + + // Test WithString compatibility + t.Run("WithString compatibility", func(t *testing.T) { + tool := NewTool("test-tool", WithString("name")) + + nameSchema := tool.InputSchema.Properties["name"] + assert.NotNil(t, nameSchema) + assert.NotNil(t, nameSchema.Value) + + // For v0.132.0, Type should be *openapi3.Types + assert.NotNil(t, nameSchema.Value.Type) + assert.IsType(t, &openapi3.Types{}, nameSchema.Value.Type) + assert.Equal(t, openapi3.Types{openapi3.TypeString}, *nameSchema.Value.Type) + }) + + // Test all other types + t.Run("All types compatibility", func(t *testing.T) { + tool := NewTool("test-tool", + WithString("str_field"), + WithNumber("num_field"), + WithInteger("int_field"), + WithBoolean("bool_field"), + WithArray("arr_field"), + WithObject("obj_field"), + ) + + testCases := []struct { + fieldName string + expectedType string + }{ + {"str_field", openapi3.TypeString}, + {"num_field", openapi3.TypeNumber}, + {"int_field", openapi3.TypeInteger}, + {"bool_field", openapi3.TypeBoolean}, + {"arr_field", openapi3.TypeArray}, + {"obj_field", openapi3.TypeObject}, + } + + for _, tc := range testCases { + t.Run(tc.fieldName, func(t *testing.T) { + schema := tool.InputSchema.Properties[tc.fieldName] + assert.NotNil(t, schema) + assert.NotNil(t, schema.Value) + assert.NotNil(t, schema.Value.Type) + assert.IsType(t, &openapi3.Types{}, schema.Value.Type) + assert.Equal(t, openapi3.Types{tc.expectedType}, *schema.Value.Type) + }) + } + }) +} + +// TestOriginalVsCompatibilityEquivalence verifies that our compatibility methods +// produce exactly the same result as the original code would for current users +func TestOriginalVsCompatibilityEquivalence(t *testing.T) { + // Simulate what the original code would have produced + originalSchema := &openapi3.Schema{ + Type: &openapi3.Types{openapi3.TypeString}, + } + + // What our compatibility layer produces + compatSchema := openapi.DefaultCompat.CreateStringSchema() + + // They should be equivalent + assert.Equal(t, *originalSchema.Type, *compatSchema.Type) + // Both should have Type field set + assert.NotNil(t, originalSchema.Type) + assert.NotNil(t, compatSchema.Type) +} diff --git a/openapi_compat.go b/openapi_compat.go deleted file mode 100644 index a7eacff..0000000 --- a/openapi_compat.go +++ /dev/null @@ -1,107 +0,0 @@ -package mcp - -import ( - "reflect" - "sync" - - "github.com/getkin/kin-openapi/openapi3" -) - -// OpenAPICompat provides version compatibility for kin-openapi -// It handles the breaking change in v0.124.0 where Schema.Type changed from string to *Types -type OpenAPICompat struct { - // Cache the type information to avoid repeated reflection - once sync.Once - typeFieldType reflect.Type - isPointerType bool - typesSliceType reflect.Type -} - -// Global instance for convenience -var compat = &OpenAPICompat{} - -// initTypeInfo performs one-time reflection to determine the API version -func (c *OpenAPICompat) initTypeInfo() { - c.once.Do(func() { - schema := &openapi3.Schema{} - v := reflect.ValueOf(schema).Elem() - typeField := v.FieldByName("Type") - - if typeField.IsValid() { - c.typeFieldType = typeField.Type() - c.isPointerType = c.typeFieldType.Kind() == reflect.Ptr - - if c.isPointerType { - // v0.124.0+: Type is *Types where Types is []string - c.typesSliceType = c.typeFieldType.Elem() - } - } - }) -} - -// SetSchemaTypeCompat sets the Type field of a schema in a version-compatible way -func (c *OpenAPICompat) SetSchemaTypeCompat(schema *openapi3.Schema, typeName string) { - if schema == nil { - return - } - - // Initialize type info once - c.initTypeInfo() - - v := reflect.ValueOf(schema).Elem() - typeField := v.FieldByName("Type") - - if !typeField.IsValid() || !typeField.CanSet() { - return - } - - if c.isPointerType { - // v0.124.0+: Type is *Types ([]string) - typesValue := reflect.New(c.typesSliceType) - typesSlice := reflect.MakeSlice(c.typesSliceType, 1, 1) - typesSlice.Index(0).SetString(typeName) - typesValue.Elem().Set(typesSlice) - typeField.Set(typesValue) - } else { - // v0.123.0-: Type is string - typeField.SetString(typeName) - } -} - -// CreateSchemaCompat creates a new schema with proper Type field -func (c *OpenAPICompat) CreateSchemaCompat(typeName string) *openapi3.Schema { - schema := &openapi3.Schema{} - c.SetSchemaTypeCompat(schema, typeName) - return schema -} - -// CreateObjectSchemaCompat creates a new object schema with properties -func (c *OpenAPICompat) CreateObjectSchemaCompat() *openapi3.Schema { - schema := &openapi3.Schema{ - Properties: make(openapi3.Schemas), - Required: []string{}, - } - c.SetSchemaTypeCompat(schema, openapi3.TypeObject) - return schema -} - -// Convenience functions for common types -func (c *OpenAPICompat) CreateStringSchemaCompat() *openapi3.Schema { - return c.CreateSchemaCompat(openapi3.TypeString) -} - -func (c *OpenAPICompat) CreateNumberSchemaCompat() *openapi3.Schema { - return c.CreateSchemaCompat(openapi3.TypeNumber) -} - -func (c *OpenAPICompat) CreateIntegerSchemaCompat() *openapi3.Schema { - return c.CreateSchemaCompat(openapi3.TypeInteger) -} - -func (c *OpenAPICompat) CreateBooleanSchemaCompat() *openapi3.Schema { - return c.CreateSchemaCompat(openapi3.TypeBoolean) -} - -func (c *OpenAPICompat) CreateArraySchemaCompat() *openapi3.Schema { - return c.CreateSchemaCompat(openapi3.TypeArray) -}