gf/protocol/goai/goai.go

209 lines
5.7 KiB
Go
Raw Normal View History

2021-10-02 18:54:06 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package goai implements and provides document generating for OpenApi specification.
//
// https://editor.swagger.io/
2021-10-02 14:52:28 +08:00
package goai
import (
"context"
2021-10-02 18:54:06 +08:00
"fmt"
2021-10-02 14:52:28 +08:00
"github.com/gogf/gf/errors/gcode"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/internal/json"
2021-10-06 21:51:21 +08:00
"github.com/gogf/gf/text/gstr"
2021-10-02 14:52:28 +08:00
"reflect"
)
// OpenApiV3 is the structure defined from:
2021-10-02 18:54:06 +08:00
// https://swagger.io/specification/
2021-10-02 14:52:28 +08:00
// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md
type OpenApiV3 struct {
Config Config `json:"-" yaml:"-"`
OpenAPI string `json:"openapi" yaml:"openapi"`
Components Components `json:"components,omitempty" yaml:"components,omitempty"`
Info Info `json:"info" yaml:"info"`
Paths Paths `json:"paths" yaml:"paths"`
Security *SecurityRequirements `json:"security,omitempty" yaml:"security,omitempty"`
Servers *Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
Tags *Tags `json:"tags,omitempty" yaml:"tags,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
// ExternalDocs is specified by OpenAPI/Swagger standard version 3.0.
type ExternalDocs struct {
URL string `json:"url,omitempty"`
Description string `json:"description,omitempty"`
}
const (
HttpMethodAll = `ALL`
2021-10-02 14:52:28 +08:00
HttpMethodGet = `GET`
HttpMethodPut = `PUT`
HttpMethodPost = `POST`
HttpMethodDelete = `DELETE`
HttpMethodConnect = `CONNECT`
HttpMethodHead = `HEAD`
HttpMethodOptions = `OPTIONS`
HttpMethodPatch = `PATCH`
HttpMethodTrace = `TRACE`
)
const (
TypeNumber = `number`
TypeBoolean = `boolean`
TypeArray = `array`
TypeString = `string`
TypeObject = `object`
FormatInt32 = `int32`
FormatInt64 = `int64`
FormatDouble = `double`
FormatByte = `byte`
FormatBinary = `binary`
FormatDate = `date`
FormatDateTime = `date-time`
FormatPassword = `password`
)
2021-10-02 18:54:06 +08:00
const (
ParameterInHeader = `header`
ParameterInPath = `path`
ParameterInQuery = `query`
ParameterInCookie = `cookie`
)
const (
2021-10-08 16:02:53 +08:00
TagNamePath = `path`
TagNameMethod = `method`
TagNameMime = `mime`
TagNameValidate = `v`
2021-10-02 18:54:06 +08:00
)
2021-10-02 15:07:47 +08:00
var (
2021-10-11 19:59:15 +08:00
defaultReadContentTypes = []string{`application/json`}
defaultWriteContentTypes = []string{`application/json`}
2021-10-02 14:52:28 +08:00
)
2021-10-02 18:54:06 +08:00
// New creates and returns a OpenApiV3 implements object.
2021-10-02 14:52:28 +08:00
func New() *OpenApiV3 {
oai := &OpenApiV3{}
oai.fillWithDefaultValue()
return oai
}
2021-10-02 18:54:06 +08:00
// AddInput is the structured parameter for function OpenApiV3.Add.
2021-10-02 14:52:28 +08:00
type AddInput struct {
2021-10-02 18:54:06 +08:00
Path string // Path specifies the custom path if this is not configured in Meta of struct tag.
2021-10-08 11:40:47 +08:00
Prefix string // Prefix specifies the custom route path prefix, which will be added with the path tag in Meta of struct tag.
2021-10-02 18:54:06 +08:00
Method string // Method specifies the custom HTTP method if this is not configured in Meta of struct tag.
Object interface{} // Object can be an instance of struct or a route function.
2021-10-02 14:52:28 +08:00
}
2021-10-02 18:54:06 +08:00
// Add adds an instance of struct or a route function to OpenApiV3 definition implements.
func (oai *OpenApiV3) Add(in AddInput) error {
2021-10-02 14:52:28 +08:00
var (
reflectValue = reflect.ValueOf(in.Object)
)
for reflectValue.Kind() == reflect.Ptr {
reflectValue = reflectValue.Elem()
}
switch reflectValue.Kind() {
case reflect.Struct:
2021-10-02 18:54:06 +08:00
return oai.addSchema(in.Object)
2021-10-02 14:52:28 +08:00
case reflect.Func:
2021-10-02 18:54:06 +08:00
return oai.addPath(addPathInput{
2021-10-02 14:52:28 +08:00
Path: in.Path,
2021-10-08 11:42:28 +08:00
Prefix: in.Prefix,
2021-10-02 14:52:28 +08:00
Method: in.Method,
Function: in.Object,
})
default:
2021-10-02 18:54:06 +08:00
return gerror.NewCodef(
2021-10-02 14:52:28 +08:00
gcode.CodeInvalidParameter,
`unsupported parameter type "%s", only struct/function type is supported`,
reflect.TypeOf(in.Object).String(),
2021-10-02 18:54:06 +08:00
)
2021-10-02 14:52:28 +08:00
}
}
func (oai OpenApiV3) String() string {
b, err := json.Marshal(oai)
if err != nil {
intlog.Error(context.TODO(), err)
}
return string(b)
}
2021-10-02 18:54:06 +08:00
2021-10-08 17:05:11 +08:00
func (oai *OpenApiV3) golangTypeToOAIType(t reflect.Type) string {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
switch t.Kind() {
case reflect.String:
return TypeString
case reflect.Struct:
switch t.String() {
case `time.Time`, `gtime.Time`:
return TypeString
}
return TypeObject
case reflect.Slice, reflect.Array:
switch t.String() {
case `[]uint8`:
return TypeString
}
return TypeArray
case reflect.Bool:
return TypeBoolean
case
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64,
reflect.Complex64, reflect.Complex128:
return TypeNumber
default:
return TypeObject
}
}
// golangTypeToOAIFormat converts and returns OpenAPI parameter format for given golang type `t`.
// Note that it does not return standard OpenAPI parameter format but custom format in golang type.
func (oai *OpenApiV3) golangTypeToOAIFormat(t reflect.Type) string {
format := t.String()
switch gstr.TrimLeft(format, "*") {
case `[]uint8`:
return FormatBinary
default:
return format
}
}
2021-10-02 18:54:06 +08:00
func formatRefToBytes(ref string) []byte {
return []byte(fmt.Sprintf(`{"$ref":"#/components/schemas/%s"}`, ref))
}
2021-10-06 21:51:21 +08:00
func golangTypeToSchemaName(t reflect.Type) string {
var (
s = gstr.TrimLeft(t.String(), "*")
)
s = gstr.ReplaceByMap(s, map[string]string{
` `: ``,
`{`: ``,
`}`: ``,
})
return s
2021-10-06 21:51:21 +08:00
}