feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
327
backend/application/base/pluginutil/api.go
Normal file
327
backend/application/base/pluginutil/api.go
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 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/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{}
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user