after fork
This commit is contained in:
8
router/enums.go
Normal file
8
router/enums.go
Normal file
@ -0,0 +1,8 @@
|
||||
package router
|
||||
|
||||
type ContentTypeType string
|
||||
|
||||
var (
|
||||
ContentTypeRequest ContentTypeType = "request"
|
||||
ContentTypeResponse ContentTypeType = "response"
|
||||
)
|
83
router/options.go
Normal file
83
router/options.go
Normal file
@ -0,0 +1,83 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"git.ma-al.com/goc_marek/fiber_docs/security"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type Option func(router *Router)
|
||||
|
||||
func Security(securities ...security.ISecurity) Option {
|
||||
return func(router *Router) {
|
||||
for _, s := range securities {
|
||||
router.Securities = append(router.Securities, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Responses(response Response) Option {
|
||||
return func(router *Router) {
|
||||
router.Response = response
|
||||
}
|
||||
}
|
||||
|
||||
func Handlers(handlers ...fiber.Handler) Option {
|
||||
return func(router *Router) {
|
||||
for _, handler := range handlers {
|
||||
router.Handlers.PushBack(handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Tags(tags ...string) Option {
|
||||
return func(router *Router) {
|
||||
if router.Tags == nil {
|
||||
router.Tags = tags
|
||||
} else {
|
||||
router.Tags = append(router.Tags, tags...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Summary(summary string) Option {
|
||||
return func(router *Router) {
|
||||
router.Summary = summary
|
||||
}
|
||||
}
|
||||
|
||||
func Description(description string) Option {
|
||||
return func(router *Router) {
|
||||
router.Description = description
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated mark api is deprecated
|
||||
func Deprecated() Option {
|
||||
return func(router *Router) {
|
||||
router.Deprecated = true
|
||||
}
|
||||
}
|
||||
|
||||
func OperationID(ID string) Option {
|
||||
return func(router *Router) {
|
||||
router.OperationID = ID
|
||||
}
|
||||
}
|
||||
|
||||
// Exclude exclude in docs
|
||||
func Exclude() Option {
|
||||
return func(router *Router) {
|
||||
router.Exclude = true
|
||||
}
|
||||
}
|
||||
|
||||
// ContentType Set request contentType
|
||||
func ContentType(contentType string, contentTypeType ContentTypeType) Option {
|
||||
return func(router *Router) {
|
||||
if contentTypeType == ContentTypeRequest {
|
||||
router.RequestContentType = contentType
|
||||
} else {
|
||||
router.ResponseContentType = contentType
|
||||
}
|
||||
}
|
||||
}
|
67
router/parser.go
Normal file
67
router/parser.go
Normal file
@ -0,0 +1,67 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
_ "unsafe"
|
||||
|
||||
"git.ma-al.com/goc_marek/fiber_docs/constants"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
//go:linkname decoderBuilder github.com/gofiber/fiber/v2.decoderBuilder
|
||||
func decoderBuilder(parserConfig fiber.ParserConfig) interface{}
|
||||
|
||||
//go:linkname equalFieldType github.com/gofiber/fiber/v2.equalFieldType
|
||||
func equalFieldType(out interface{}, kind reflect.Kind, key string) bool
|
||||
|
||||
func ParseToStruct(aliasTag string, out interface{}, data map[string][]string) error {
|
||||
decoder := decoderBuilder(fiber.ParserConfig{
|
||||
SetAliasTag: aliasTag,
|
||||
IgnoreUnknownKeys: true,
|
||||
})
|
||||
result := reflect.ValueOf(decoder).
|
||||
MethodByName("Decode").
|
||||
Call([]reflect.Value{reflect.ValueOf(out), reflect.ValueOf(data)})
|
||||
switch result[0].Interface().(type) {
|
||||
case error:
|
||||
return result[0].Interface().(error)
|
||||
case nil:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func HeaderParser(c *fiber.Ctx, model interface{}) error {
|
||||
headerData := make(map[string][]string)
|
||||
c.Request().Header.VisitAll(func(key, val []byte) {
|
||||
k := utils.UnsafeString(key)
|
||||
v := utils.UnsafeString(val)
|
||||
if strings.Contains(v, ",") && equalFieldType(model, reflect.Slice, k) {
|
||||
values := strings.Split(v, ",")
|
||||
for i := 0; i < len(values); i++ {
|
||||
headerData[k] = append(headerData[k], values[i])
|
||||
}
|
||||
} else {
|
||||
headerData[k] = append(headerData[k], v)
|
||||
}
|
||||
})
|
||||
return ParseToStruct(constants.HEADER, model, headerData)
|
||||
}
|
||||
|
||||
func ParamsParser(c *fiber.Ctx, model interface{}) error {
|
||||
params := make(map[string][]string)
|
||||
for _, param := range c.Route().Params {
|
||||
params[param] = append(params[param], c.Params(param))
|
||||
}
|
||||
return ParseToStruct(constants.URI, model, params)
|
||||
}
|
||||
|
||||
func CookiesParser(c *fiber.Ctx, model interface{}) error {
|
||||
params := make(map[string][]string)
|
||||
c.Request().Header.VisitAllCookie(func(key, value []byte) {
|
||||
params[string(key)] = append(params[string(key)], string(value))
|
||||
})
|
||||
return ParseToStruct(constants.COOKIE, model, params)
|
||||
}
|
11
router/responses.go
Normal file
11
router/responses.go
Normal file
@ -0,0 +1,11 @@
|
||||
package router
|
||||
|
||||
import "github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
type Response map[string]ResponseItem
|
||||
|
||||
type ResponseItem struct {
|
||||
Description string
|
||||
Model interface{}
|
||||
Headers openapi3.Headers
|
||||
}
|
160
router/router.go
Normal file
160
router/router.go
Normal file
@ -0,0 +1,160 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"reflect"
|
||||
|
||||
"git.ma-al.com/goc_marek/fiber_docs/security"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/mcuadros/go-defaults"
|
||||
)
|
||||
|
||||
type Model any
|
||||
|
||||
type Router struct {
|
||||
Handlers *list.List
|
||||
Path string
|
||||
Method string
|
||||
Summary string
|
||||
Description string
|
||||
Deprecated bool
|
||||
RequestContentType string
|
||||
ResponseContentType string
|
||||
Tags []string
|
||||
API fiber.Handler
|
||||
Model Model
|
||||
OperationID string
|
||||
Exclude bool
|
||||
Securities []security.ISecurity
|
||||
Response Response
|
||||
}
|
||||
|
||||
var validate = validator.New()
|
||||
|
||||
func BindModel(req interface{}) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
model := reflect.New(reflect.TypeOf(req).Elem()).Interface()
|
||||
if err := HeaderParser(c, model); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := CookiesParser(c, model); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.QueryParser(model); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Method() == fiber.MethodPost || c.Method() == fiber.MethodPut {
|
||||
if err := c.BodyParser(model); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := ParamsParser(c, model); err != nil {
|
||||
return err
|
||||
}
|
||||
defaults.SetDefaults(model)
|
||||
if err := validate.Struct(model); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := copier.Copy(req, model); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func (router *Router) GetHandlers() []fiber.Handler {
|
||||
var handlers []fiber.Handler
|
||||
for _, s := range router.Securities {
|
||||
handlers = append(handlers, s.Authorize)
|
||||
}
|
||||
for h := router.Handlers.Front(); h != nil; h = h.Next() {
|
||||
if f, ok := h.Value.(fiber.Handler); ok {
|
||||
handlers = append(handlers, f)
|
||||
}
|
||||
}
|
||||
handlers = append(handlers, router.API)
|
||||
return handlers
|
||||
}
|
||||
func NewX(f fiber.Handler, options ...Option) *Router {
|
||||
r := &Router{
|
||||
Handlers: list.New(),
|
||||
Response: make(Response),
|
||||
API: func(ctx *fiber.Ctx) error {
|
||||
return f(ctx)
|
||||
},
|
||||
}
|
||||
for _, option := range options {
|
||||
option(r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
func New[T Model, F func(c *fiber.Ctx, req T) error](f F, options ...Option) *Router {
|
||||
var model T
|
||||
h := BindModel(&model)
|
||||
r := &Router{
|
||||
Handlers: list.New(),
|
||||
Response: make(Response),
|
||||
API: func(ctx *fiber.Ctx) error {
|
||||
return f(ctx, model)
|
||||
},
|
||||
Model: model,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(r)
|
||||
}
|
||||
|
||||
r.Handlers.PushBack(h)
|
||||
return r
|
||||
}
|
||||
|
||||
func (router *Router) WithSecurity(securities ...security.ISecurity) *Router {
|
||||
Security(securities...)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithResponses(response Response) *Router {
|
||||
Responses(response)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithHandlers(handlers ...fiber.Handler) *Router {
|
||||
Handlers(handlers...)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithTags(tags ...string) *Router {
|
||||
Tags(tags...)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithSummary(summary string) *Router {
|
||||
Summary(summary)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithDescription(description string) *Router {
|
||||
Description(description)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithDeprecated() *Router {
|
||||
Deprecated()(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithOperationID(ID string) *Router {
|
||||
OperationID(ID)(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithExclude() *Router {
|
||||
Exclude()(router)
|
||||
return router
|
||||
}
|
||||
|
||||
func (router *Router) WithContentType(contentType string, contentTypeType ContentTypeType) *Router {
|
||||
ContentType(contentType, contentTypeType)(router)
|
||||
return router
|
||||
}
|
Reference in New Issue
Block a user