after fork

This commit is contained in:
2023-04-11 22:43:48 +02:00
commit 6486bfd1c8
33 changed files with 3366 additions and 0 deletions

8
router/enums.go Normal file
View File

@ -0,0 +1,8 @@
package router
type ContentTypeType string
var (
ContentTypeRequest ContentTypeType = "request"
ContentTypeResponse ContentTypeType = "response"
)

83
router/options.go Normal file
View 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
View 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
View 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
View 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
}