123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- // 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/
- package goai
- import (
- "context"
- "fmt"
- "reflect"
- "github.com/gogf/gf/v2/errors/gcode"
- "github.com/gogf/gf/v2/errors/gerror"
- "github.com/gogf/gf/v2/internal/intlog"
- "github.com/gogf/gf/v2/internal/json"
- "github.com/gogf/gf/v2/text/gstr"
- )
- // OpenApiV3 is the structure defined from:
- // https://swagger.io/specification/
- // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md
- type OpenApiV3 struct {
- Config Config `json:"-"`
- OpenAPI string `json:"openapi"`
- Components Components `json:"components,omitempty"`
- Info Info `json:"info"`
- Paths Paths `json:"paths"`
- Security *SecurityRequirements `json:"security,omitempty"`
- Servers *Servers `json:"servers,omitempty"`
- Tags *Tags `json:"tags,omitempty"`
- ExternalDocs *ExternalDocs `json:"externalDocs,omitempty"`
- }
- const (
- HttpMethodGet = `GET`
- HttpMethodPut = `PUT`
- HttpMethodPost = `POST`
- HttpMethodDelete = `DELETE`
- HttpMethodConnect = `CONNECT`
- HttpMethodHead = `HEAD`
- HttpMethodOptions = `OPTIONS`
- HttpMethodPatch = `PATCH`
- HttpMethodTrace = `TRACE`
- )
- const (
- TypeInteger = `integer`
- 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`
- )
- const (
- ParameterInHeader = `header`
- ParameterInPath = `path`
- ParameterInQuery = `query`
- ParameterInCookie = `cookie`
- )
- const (
- TagNamePath = `path`
- TagNameMethod = `method`
- TagNameMime = `mime`
- TagNameConsumes = `consumes`
- TagNameType = `type`
- TagNameDomain = `domain`
- )
- const (
- validationRuleKeyForRequired = `required`
- validationRuleKeyForIn = `in:`
- )
- var (
- defaultReadContentTypes = []string{`application/json`}
- defaultWriteContentTypes = []string{`application/json`}
- shortTypeMapForTag = map[string]string{
- "d": "Default",
- "sum": "Summary",
- "sm": "Summary",
- "des": "Description",
- "dc": "Description",
- "eg": "Example",
- "egs": "Examples",
- "ed": "ExternalDocs",
- }
- )
- // New creates and returns a OpenApiV3 implements object.
- func New() *OpenApiV3 {
- oai := &OpenApiV3{}
- oai.fillWithDefaultValue()
- return oai
- }
- // AddInput is the structured parameter for function OpenApiV3.Add.
- type AddInput struct {
- Path string // Path specifies the custom path if this is not configured in Meta of struct tag.
- Prefix string // Prefix specifies the custom route path prefix, which will be added with the path tag in Meta of struct tag.
- 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.
- }
- // Add adds an instance of struct or a route function to OpenApiV3 definition implements.
- func (oai *OpenApiV3) Add(in AddInput) error {
- var (
- reflectValue = reflect.ValueOf(in.Object)
- )
- for reflectValue.Kind() == reflect.Ptr {
- reflectValue = reflectValue.Elem()
- }
- switch reflectValue.Kind() {
- case reflect.Struct:
- return oai.addSchema(in.Object)
- case reflect.Func:
- return oai.addPath(addPathInput{
- Path: in.Path,
- Prefix: in.Prefix,
- Method: in.Method,
- Function: in.Object,
- })
- default:
- return gerror.NewCodef(
- gcode.CodeInvalidParameter,
- `unsupported parameter type "%s", only struct/function type is supported`,
- reflect.TypeOf(in.Object).String(),
- )
- }
- }
- func (oai OpenApiV3) String() string {
- b, err := json.Marshal(oai)
- if err != nil {
- intlog.Errorf(context.TODO(), `%+v`, err)
- }
- return string(b)
- }
- 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:
- return TypeInteger
- case
- 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:
- if oai.isEmbeddedStructDefinition(t) {
- return `EmbeddedStructDefinition`
- }
- return format
- }
- }
- func (oai *OpenApiV3) golangTypeToSchemaName(t reflect.Type) string {
- var (
- pkgPath string
- schemaName = gstr.TrimLeft(t.String(), "*")
- )
- // Pointer type has no PkgPath.
- for t.Kind() == reflect.Ptr {
- t = t.Elem()
- }
- if pkgPath = t.PkgPath(); pkgPath != "" && pkgPath != "." {
- if !oai.Config.IgnorePkgPath {
- schemaName = gstr.Replace(pkgPath, `/`, `.`) + gstr.SubStrFrom(schemaName, ".")
- }
- }
- schemaName = gstr.ReplaceByMap(schemaName, map[string]string{
- ` `: ``,
- `{`: ``,
- `}`: ``,
- })
- return schemaName
- }
- func (oai *OpenApiV3) fileMapWithShortTags(m map[string]string) map[string]string {
- for k, v := range shortTypeMapForTag {
- if m[v] == "" && m[k] != "" {
- m[v] = m[k]
- }
- }
- return m
- }
- func formatRefToBytes(ref string) []byte {
- return []byte(fmt.Sprintf(`{"$ref":"#/components/schemas/%s"}`, ref))
- }
- func isValidParameterName(key string) bool {
- return key != "-"
- }
|