echoswagger/internal.go

185 lines
4.3 KiB
Go

/*
* Copyright (c) 2019 Alex aka mailoman <alex@webz.asia>
*
* 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.
*
* @author Alex aka mailoman <alex@webz.asia>
* @copyright Copyright (c) 2019 Alex aka mailoman <alex@webz.asia>
* @since 18.12.2019
*
*/
package echoswagger
import (
"bytes"
"encoding/json"
"html/template"
"net/http"
"reflect"
"github.com/labstack/echo/v4"
)
type ParamInType string
const (
ParamInQuery ParamInType = "query"
ParamInHeader ParamInType = "header"
ParamInPath ParamInType = "path"
ParamInFormData ParamInType = "formData"
ParamInBody ParamInType = "body"
)
type UISetting struct {
DetachSpec bool
HideTop bool
CDN string
}
type RawDefineDic map[string]RawDefine
type RawDefine struct {
Value reflect.Value
Schema *JSONSchema
}
func (r *Root) docHandler(docPath string) echo.HandlerFunc {
t, err := template.New("swagger").Parse(SwaggerUIContent)
if err != nil {
panic(err)
}
return func(c echo.Context) error {
cdn := r.ui.CDN
if cdn == "" {
cdn = DefaultCDN
}
buf := new(bytes.Buffer)
params := map[string]interface{}{
"title": r.spec.Info.Title,
"cdn": cdn,
"specName": SpecName,
}
if !r.ui.DetachSpec {
spec, err := r.GetSpec(c, docPath)
if err != nil {
return c.String(http.StatusInternalServerError, err.Error())
}
b, err := json.Marshal(spec)
if err != nil {
return c.String(http.StatusInternalServerError, err.Error())
}
params["spec"] = string(b)
params["docPath"] = docPath
params["hideTop"] = true
} else {
params["hideTop"] = r.ui.HideTop
}
t.Execute(buf, params)
return c.HTMLBlob(http.StatusOK, buf.Bytes())
}
}
func (r *RawDefineDic) getKey(v reflect.Value) (bool, string) {
for k, d := range *r {
if reflect.DeepEqual(d.Value.Interface(), v.Interface()) {
return true, k
}
}
name := v.Type().Name()
for k := range *r {
if name == k {
name += "_"
}
}
return false, name
}
func (r *routers) appendRoute(route *echo.Route) *api {
opr := Operation{
Responses: make(map[string]*Response),
}
a := api{
route: route,
defs: r.defs,
operation: opr,
}
r.apis = append(r.apis, a)
return &r.apis[len(r.apis)-1]
}
func (g *api) addParams(p interface{}, in ParamInType, name, desc string, required, nest bool) Api {
if !isValidParam(reflect.TypeOf(p), nest, false) {
panic("echoswagger: invalid " + string(in) + " param")
}
rt := indirectType(p)
st, sf := toSwaggerType(rt)
if st == "object" && sf == "object" {
for i := 0; i < rt.NumField(); i++ {
pm := Parameter{}.generate(rt.Field(i), in)
if pm != nil {
pm.Name = g.operation.rename(pm.Name)
g.operation.Parameters = append(g.operation.Parameters, pm)
}
}
} else {
name = g.operation.rename(name)
pm := &Parameter{
Name: name,
In: string(in),
Description: desc,
Required: required,
Type: st,
}
if st == "array" {
pm.Items = Items{}.generate(rt.Elem())
pm.CollectionFormat = "multi"
} else {
pm.Format = sf
}
g.operation.Parameters = append(g.operation.Parameters, pm)
}
return g
}
func (g *api) addBodyParams(p interface{}, name, desc string, required bool) Api {
if !isValidSchema(reflect.TypeOf(p), false) {
panic("echoswagger: invalid body parameter")
}
for _, param := range g.operation.Parameters {
if param.In == string(ParamInBody) {
panic("echoswagger: multiple body parameters are not allowed")
}
}
rv := indirectValue(p)
pm := &Parameter{
Name: name,
In: string(ParamInBody),
Description: desc,
Required: required,
Schema: g.defs.genSchema(rv),
}
g.operation.Parameters = append(g.operation.Parameters, pm)
return g
}
func (o Operation) rename(s string) string {
for _, p := range o.Parameters {
if p.Name == s {
return o.rename(s + "_")
}
}
return s
}