338 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package pluginutil
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"strconv"
 | |
| 
 | |
| 	"github.com/getkin/kin-openapi/openapi3"
 | |
| 
 | |
| 	"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
 | |
| 
 | |
| 	"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
 | |
| 	common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/errorx"
 | |
| 	"github.com/coze-dev/coze-studio/backend/types/errno"
 | |
| )
 | |
| 
 | |
| func APIParamsToOpenapiOperation(reqParams, respParams []*common.APIParameter) (*openapi3.Operation, error) {
 | |
| 	op := &openapi3.Operation{}
 | |
| 
 | |
| 	if reqParams != nil && len(reqParams) == 0 {
 | |
| 		op.Parameters = []*openapi3.ParameterRef{}
 | |
| 		op.RequestBody = entity.DefaultOpenapi3RequestBody()
 | |
| 	}
 | |
| 	if respParams != nil && len(respParams) == 0 {
 | |
| 		op.Responses = entity.DefaultOpenapi3Responses()
 | |
| 	}
 | |
| 
 | |
| 	hasSetReqBody := false
 | |
| 	hasSetParams := false
 | |
| 
 | |
| 	for _, apiParam := range reqParams {
 | |
| 		if apiParam.Location != common.ParameterLocation_Body {
 | |
| 			if !hasSetParams {
 | |
| 				hasSetParams = true
 | |
| 				op.Parameters = []*openapi3.ParameterRef{}
 | |
| 			}
 | |
| 
 | |
| 			_apiParam, err := toOpenapiParameter(apiParam)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			op.Parameters = append(op.Parameters, &openapi3.ParameterRef{
 | |
| 				Value: _apiParam,
 | |
| 			})
 | |
| 
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		var mType *openapi3.MediaType
 | |
| 		if hasSetReqBody {
 | |
| 			mType = op.RequestBody.Value.Content[plugin.MediaTypeJson]
 | |
| 		} else {
 | |
| 			hasSetReqBody = true
 | |
| 			mType = &openapi3.MediaType{
 | |
| 				Schema: &openapi3.SchemaRef{
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type:       openapi3.TypeObject,
 | |
| 						Properties: map[string]*openapi3.SchemaRef{},
 | |
| 					},
 | |
| 				},
 | |
| 			}
 | |
| 			op.RequestBody = &openapi3.RequestBodyRef{
 | |
| 				Value: &openapi3.RequestBody{
 | |
| 					Content: map[string]*openapi3.MediaType{
 | |
| 						plugin.MediaTypeJson: mType,
 | |
| 					},
 | |
| 				},
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		_apiParam, err := toOpenapi3Schema(apiParam)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		mType.Schema.Value.Properties[apiParam.Name] = &openapi3.SchemaRef{
 | |
| 			Value: _apiParam,
 | |
| 		}
 | |
| 		if apiParam.IsRequired {
 | |
| 			mType.Schema.Value.Required = append(mType.Schema.Value.Required, apiParam.Name)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	hasSetRespBody := false
 | |
| 
 | |
| 	for _, apiParam := range respParams {
 | |
| 		if !hasSetRespBody {
 | |
| 			hasSetRespBody = true
 | |
| 			op.Responses = map[string]*openapi3.ResponseRef{
 | |
| 				strconv.Itoa(http.StatusOK): {
 | |
| 					Value: &openapi3.Response{
 | |
| 						Content: map[string]*openapi3.MediaType{
 | |
| 							plugin.MediaTypeJson: {
 | |
| 								Schema: &openapi3.SchemaRef{
 | |
| 									Value: &openapi3.Schema{
 | |
| 										Type:       openapi3.TypeObject,
 | |
| 										Properties: map[string]*openapi3.SchemaRef{},
 | |
| 									},
 | |
| 								},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		_apiParam, err := toOpenapi3Schema(apiParam)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		resp, _ := op.Responses[strconv.Itoa(http.StatusOK)]
 | |
| 		mType, _ := resp.Value.Content[plugin.MediaTypeJson] // only support application/json
 | |
| 		mType.Schema.Value.Properties[apiParam.Name] = &openapi3.SchemaRef{
 | |
| 			Value: _apiParam,
 | |
| 		}
 | |
| 
 | |
| 		if apiParam.IsRequired {
 | |
| 			mType.Schema.Value.Required = append(mType.Schema.Value.Required, apiParam.Name)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return op, nil
 | |
| }
 | |
| 
 | |
| func toOpenapiParameter(apiParam *common.APIParameter) (*openapi3.Parameter, error) {
 | |
| 	paramType, ok := plugin.ToOpenapiParamType(apiParam.Type)
 | |
| 	if !ok {
 | |
| 		return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 			errorx.KVf(errno.PluginMsgKey, "the type '%s' of field '%s' is invalid", apiParam.Type, apiParam.Name))
 | |
| 	}
 | |
| 
 | |
| 	if paramType == openapi3.TypeObject {
 | |
| 		return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 			errorx.KVf(errno.PluginMsgKey, "the type of field '%s' cannot be 'object'", apiParam.Name))
 | |
| 	}
 | |
| 
 | |
| 	paramSchema := &openapi3.Schema{
 | |
| 		Type:    paramType,
 | |
| 		Default: apiParam.GlobalDefault,
 | |
| 		Extensions: map[string]interface{}{
 | |
| 			plugin.APISchemaExtendGlobalDisable: apiParam.GlobalDisable,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	if paramType == openapi3.TypeArray {
 | |
| 		if apiParam.Location == common.ParameterLocation_Path {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the type of field '%s' cannot be 'array'", apiParam.Name))
 | |
| 		}
 | |
| 		if len(apiParam.SubParameters) == 0 {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the sub parameters of field '%s' is required", apiParam.Name))
 | |
| 		}
 | |
| 
 | |
| 		arrayItem := apiParam.SubParameters[0]
 | |
| 		arrayItemType, ok := plugin.ToOpenapiParamType(arrayItem.Type)
 | |
| 		if !ok {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the item type '%s' of field '%s' is invalid", arrayItemType, apiParam.Name))
 | |
| 		}
 | |
| 
 | |
| 		if arrayItemType == openapi3.TypeObject || arrayItemType == openapi3.TypeArray {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the item type of field '%s' cannot be 'array' or 'object'", apiParam.Name))
 | |
| 		}
 | |
| 
 | |
| 		itemSchema := &openapi3.Schema{
 | |
| 			Type:        arrayItemType,
 | |
| 			Description: arrayItem.Desc,
 | |
| 			Extensions:  map[string]any{},
 | |
| 		}
 | |
| 
 | |
| 		if arrayItem.GetAssistType() > 0 {
 | |
| 			aType, ok := plugin.ToAPIAssistType(arrayItem.GetAssistType())
 | |
| 			if !ok {
 | |
| 				return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 					errorx.KVf(errno.PluginMsgKey, "the assist type '%s' of field '%s' is invalid", arrayItem.GetAssistType(), apiParam.Name))
 | |
| 			}
 | |
| 			itemSchema.Extensions[plugin.APISchemaExtendAssistType] = aType
 | |
| 			format, ok := plugin.AssistTypeToFormat(aType)
 | |
| 			if !ok {
 | |
| 				return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 					errorx.KVf(errno.PluginMsgKey, "the assist type '%s' of field '%s' is invalid", aType, apiParam.Name))
 | |
| 			}
 | |
| 			itemSchema.Format = format
 | |
| 		}
 | |
| 
 | |
| 		paramSchema.Items = &openapi3.SchemaRef{
 | |
| 			Value: itemSchema,
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if apiParam.LocalDefault != nil && *apiParam.LocalDefault != "" {
 | |
| 		paramSchema.Default = apiParam.LocalDefault
 | |
| 	}
 | |
| 	if apiParam.LocalDisable {
 | |
| 		paramSchema.Extensions[plugin.APISchemaExtendLocalDisable] = true
 | |
| 	}
 | |
| 	if apiParam.VariableRef != nil && *apiParam.VariableRef != "" {
 | |
| 		paramSchema.Extensions[plugin.APISchemaExtendVariableRef] = apiParam.VariableRef
 | |
| 	}
 | |
| 
 | |
| 	if apiParam.GetAssistType() > 0 {
 | |
| 		aType, ok := plugin.ToAPIAssistType(apiParam.GetAssistType())
 | |
| 		if !ok {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the assist type '%s' of field '%s' is invalid", apiParam.GetAssistType(), apiParam.Name))
 | |
| 		}
 | |
| 		paramSchema.Extensions[plugin.APISchemaExtendAssistType] = aType
 | |
| 		format, ok := plugin.AssistTypeToFormat(aType)
 | |
| 		if !ok {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the assist type '%s' of field '%s' is invalid", aType, apiParam.Name))
 | |
| 		}
 | |
| 		paramSchema.Format = format
 | |
| 	}
 | |
| 
 | |
| 	loc, ok := plugin.ToHTTPParamLocation(apiParam.Location)
 | |
| 	if !ok {
 | |
| 		return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 			errorx.KVf(errno.PluginMsgKey, "the location '%s' of field '%s' is invalid ", apiParam.Location, apiParam.Name))
 | |
| 	}
 | |
| 
 | |
| 	param := &openapi3.Parameter{
 | |
| 		Description: apiParam.Desc,
 | |
| 		Name:        apiParam.Name,
 | |
| 		In:          string(loc),
 | |
| 		Required:    apiParam.IsRequired,
 | |
| 		Schema: &openapi3.SchemaRef{
 | |
| 			Value: paramSchema,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	return param, nil
 | |
| }
 | |
| 
 | |
| func toOpenapi3Schema(apiParam *common.APIParameter) (*openapi3.Schema, error) {
 | |
| 	paramType, ok := plugin.ToOpenapiParamType(apiParam.Type)
 | |
| 	if !ok {
 | |
| 		return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 			errorx.KVf(errno.PluginMsgKey, "the type '%s' of field '%s' is invalid", apiParam.Type, apiParam.Name))
 | |
| 	}
 | |
| 
 | |
| 	sc := &openapi3.Schema{
 | |
| 		Description: apiParam.Desc,
 | |
| 		Type:        paramType,
 | |
| 		Default:     apiParam.GlobalDefault,
 | |
| 		Extensions: map[string]interface{}{
 | |
| 			plugin.APISchemaExtendGlobalDisable: apiParam.GlobalDisable,
 | |
| 		},
 | |
| 	}
 | |
| 	if apiParam.LocalDefault != nil && *apiParam.LocalDefault != "" {
 | |
| 		sc.Default = apiParam.LocalDefault
 | |
| 	}
 | |
| 	if apiParam.LocalDisable {
 | |
| 		sc.Extensions[plugin.APISchemaExtendLocalDisable] = true
 | |
| 	}
 | |
| 	if apiParam.VariableRef != nil && *apiParam.VariableRef != "" {
 | |
| 		sc.Extensions[plugin.APISchemaExtendVariableRef] = apiParam.VariableRef
 | |
| 	}
 | |
| 
 | |
| 	if apiParam.GetAssistType() > 0 {
 | |
| 		aType, ok := plugin.ToAPIAssistType(apiParam.GetAssistType())
 | |
| 		if !ok {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the assist type '%s' of field '%s' is invalid", apiParam.GetAssistType(), apiParam.Name))
 | |
| 		}
 | |
| 		sc.Extensions[plugin.APISchemaExtendAssistType] = aType
 | |
| 		format, ok := plugin.AssistTypeToFormat(aType)
 | |
| 		if !ok {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the assist type '%s' of field '%s' is invalid", aType, apiParam.Name))
 | |
| 		}
 | |
| 		sc.Format = format
 | |
| 	}
 | |
| 
 | |
| 	switch paramType {
 | |
| 	case openapi3.TypeObject:
 | |
| 		sc.Properties = map[string]*openapi3.SchemaRef{}
 | |
| 		for _, subParam := range apiParam.SubParameters {
 | |
| 			_subParam, err := toOpenapi3Schema(subParam)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			sc.Properties[subParam.Name] = &openapi3.SchemaRef{
 | |
| 				Value: _subParam,
 | |
| 			}
 | |
| 			if subParam.IsRequired {
 | |
| 				sc.Required = append(sc.Required, subParam.Name)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return sc, nil
 | |
| 
 | |
| 	case openapi3.TypeArray:
 | |
| 		if len(apiParam.SubParameters) == 0 {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the sub-parameters of field '%s' are required", apiParam.Name))
 | |
| 		}
 | |
| 
 | |
| 		arrayItem := apiParam.SubParameters[0]
 | |
| 		itemType, ok := plugin.ToOpenapiParamType(arrayItem.Type)
 | |
| 		if !ok {
 | |
| 			return nil, errorx.New(errno.ErrPluginInvalidParamCode,
 | |
| 				errorx.KVf(errno.PluginMsgKey, "the item type '%s' of field '%s' is invalid", itemType, apiParam.Name))
 | |
| 		}
 | |
| 
 | |
| 		subParam, err := toOpenapi3Schema(arrayItem)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		sc.Items = &openapi3.SchemaRef{
 | |
| 			Value: subParam,
 | |
| 		}
 | |
| 
 | |
| 		return sc, nil
 | |
| 	}
 | |
| 
 | |
| 	return sc, nil
 | |
| }
 |