doc-generate/internal/swagger/response.go

202 lines
5.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package swagger
import (
"net/http"
"strings"
"github.com/go-openapi/spec"
apiSpec "github.com/zeromicro/go-zero/tools/goctl/api/spec"
)
func jsonResponseFromType(ctx Context, atDoc apiSpec.AtDoc, tp apiSpec.Type) *spec.Responses {
return jsonResponseFromTypeWithDocs(ctx, atDoc, tp, nil)
}
func jsonResponseFromTypeWithDocs(ctx Context, atDoc apiSpec.AtDoc, tp apiSpec.Type, handlerDoc apiSpec.Doc) *spec.Responses {
// 首先檢查是否有 @respdoc 註解(從 handlerDoc 或 atDoc
var respDocs []RespDoc
if len(handlerDoc) > 0 {
respDocs = parseRespDocsFromDoc(handlerDoc)
}
if len(respDocs) == 0 {
respDocs = parseRespDocs(atDoc)
}
if len(respDocs) > 0 {
return jsonResponseFromRespDocs(ctx, atDoc, respDocs, tp)
}
// 原有邏輯:使用默認的 200 回應
if tp == nil {
return &spec.Responses{
ResponsesProps: spec.ResponsesProps{
StatusCodeResponses: map[int]spec.Response{
http.StatusOK: {
ResponseProps: spec.ResponseProps{
Description: "",
Schema: &spec.Schema{},
},
},
},
},
}
}
props := spec.SchemaProps{
AdditionalProperties: mapFromGoType(ctx, tp),
Items: itemsFromGoType(ctx, tp),
}
if ctx.UseDefinitions {
structName, ok := containsStruct(tp)
if ok {
props.Ref = spec.MustCreateRef(getRefName(structName))
return &spec.Responses{
ResponsesProps: spec.ResponsesProps{
StatusCodeResponses: map[int]spec.Response{
http.StatusOK: {
ResponseProps: spec.ResponseProps{
Schema: &spec.Schema{
SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
},
},
},
},
},
}
}
}
p, _ := propertiesFromType(ctx, tp)
props.Type = typeFromGoType(ctx, tp)
props.Properties = p
return &spec.Responses{
ResponsesProps: spec.ResponsesProps{
StatusCodeResponses: map[int]spec.Response{
http.StatusOK: {
ResponseProps: spec.ResponseProps{
Schema: &spec.Schema{
SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
},
},
},
},
},
}
}
// jsonResponseFromRespDocs 從 @respdoc 註解生成多狀態碼回應
func jsonResponseFromRespDocs(ctx Context, atDoc apiSpec.AtDoc, respDocs []RespDoc, defaultType apiSpec.Type) *spec.Responses {
responses := &spec.Responses{
ResponsesProps: spec.ResponsesProps{
StatusCodeResponses: make(map[int]spec.Response),
},
}
for _, respDoc := range respDocs {
// 如果有單一 Schema直接使用
if respDoc.Schema != "" {
tp := findTypeByName(ctx.Api, respDoc.Schema)
if tp == nil && respDoc.StatusCode == http.StatusOK && defaultType != nil {
// 如果找不到類型且是 200使用默認類型
tp = defaultType
}
response := createResponseFromType(ctx, atDoc, tp, respDoc.Description)
responses.StatusCodeResponses[respDoc.StatusCode] = response
continue
}
// 如果有多個業務錯誤碼BizCodes為 Swagger 2.0 創建一個通用回應
// OpenAPI 3.0 會在 convertSwagger2ToOpenAPI3 中特殊處理
if len(respDoc.BizCodes) > 0 {
// 對於 Swagger 2.0,我們使用 oneOf/anyOf 概念的註釋
// 但 Swagger 2.0 不支持 oneOf所以使用第一個類型作為示例
// 並在描述中列出所有可能的類型
var firstType apiSpec.Type
descriptions := []string{}
for code, bizCode := range respDoc.BizCodes {
tp := findTypeByName(ctx.Api, bizCode.Schema)
if firstType == nil && tp != nil {
firstType = tp
}
desc := code + ": " + bizCode.Schema
if bizCode.Description != "" {
desc += " - " + bizCode.Description
}
descriptions = append(descriptions, desc)
}
description := respDoc.Description
if len(descriptions) > 0 {
if description != "" {
description += "\n\n"
}
description += "Possible errors:\n" + strings.Join(descriptions, "\n")
}
response := createResponseFromType(ctx, atDoc, firstType, description)
// 在 VendorExtensible 中存儲業務錯誤碼信息,供 OpenAPI 3.0 使用
if response.Extensions == nil {
response.Extensions = make(spec.Extensions)
}
response.Extensions["x-biz-codes"] = respDoc.BizCodes
responses.StatusCodeResponses[respDoc.StatusCode] = response
}
}
// 如果沒有定義 200 回應,添加默認的
if _, ok := responses.StatusCodeResponses[http.StatusOK]; !ok && defaultType != nil {
responses.StatusCodeResponses[http.StatusOK] = createResponseFromType(ctx, atDoc, defaultType, "")
}
return responses
}
// createResponseFromType 從類型創建回應對象
func createResponseFromType(ctx Context, atDoc apiSpec.AtDoc, tp apiSpec.Type, description string) spec.Response {
if tp == nil {
return spec.Response{
ResponseProps: spec.ResponseProps{
Description: description,
Schema: &spec.Schema{},
},
}
}
props := spec.SchemaProps{
AdditionalProperties: mapFromGoType(ctx, tp),
Items: itemsFromGoType(ctx, tp),
}
if ctx.UseDefinitions {
structName, ok := containsStruct(tp)
if ok {
props.Ref = spec.MustCreateRef(getRefName(structName))
return spec.Response{
ResponseProps: spec.ResponseProps{
Description: description,
Schema: &spec.Schema{
SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
},
},
}
}
}
p, _ := propertiesFromType(ctx, tp)
props.Type = typeFromGoType(ctx, tp)
props.Properties = p
return spec.Response{
ResponseProps: spec.ResponseProps{
Description: description,
Schema: &spec.Schema{
SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
},
},
}
}