Files
kubevela/pkg/server/util/middleware.go
zzxwill 53164a4d2f Implement API for generating OpenAPI schema for definition
Fetched cue parameters from workloaddefinition/traitdefinition, generated
OpenAPI v3 schema, fixed problems of tainted `description` filed, added filed
"title" required by form-render component, added it in API server router

To fix #680
2021-01-05 21:57:38 +08:00

134 lines
3.4 KiB
Go

package util
import (
"context"
"mime"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap/zapcore"
)
// Header Keys
const (
// ContextKey is used as key to set/get context.
ContextKey = "context"
// ContentTypeJSON : json
ContentTypeJSON = "application/json"
// ContentTypeOctetStream: octet stream
ContentTypeOctetStream = "application/octet-stream"
// HeaderTraceID is header name for trace id.
HeaderTraceID = "x-fc-trace-id"
HeaderContentType = "content-Type"
HeaderContentLength = "content-Length"
// HeaderClientIP is the real IP of the remote client
HeaderClientIP = "clientIP"
)
// ContextKeyType defining the context key type for the middleware
type ContextKeyType string
const (
// ServiceLogFields shared key service log fields
ServiceLogFields ContextKeyType = "ServiceLogFields"
// HeaderRequestID is used as key to set/get request id.
HeaderRequestID ContextKeyType = "x-fc-request-id"
)
// RESTful API paths
const (
RootPath = "/api"
EnvironmentPath = "/envs"
ApplicationPath = "/apps"
WorkloadDefinitionPath = "/workloads"
ScopeDefinitionPath = "/scopes"
TraitDefinitionPath = "/traits"
CapabilityPath = "/capabilities"
CapabilityCenterPath = "/capability-centers"
VersionPath = "/version"
Definition = "/definitions"
)
// NoRoute is a handler which is invoked when there is no route matches.
func NoRoute() gin.HandlerFunc {
return func(c *gin.Context) {
SetErrorAndAbort(c, PathNotSupported, c.Request.Method, c.Request.URL.Path)
}
}
// generateRequestID :Get request id
func generateRequestID() string {
id, _ := uuid.NewV4()
return id.String()
}
// SetRequestID ...
func SetRequestID() gin.HandlerFunc {
return func(c *gin.Context) {
requestID := ""
traceID := ""
if traceID = c.Request.Header.Get(HeaderTraceID); traceID != "" {
requestID = traceID
} else if requestID = c.Request.Header.Get(string(HeaderRequestID)); requestID != "" {
traceID = requestID
} else {
requestID = generateRequestID()
traceID = requestID
}
c.Set(string(HeaderRequestID), requestID)
c.Set(HeaderClientIP, c.ClientIP())
c.Set(HeaderTraceID, traceID)
}
}
// SetContext :Set context metadata for request
// Before get request
func SetContext() gin.HandlerFunc {
return func(c *gin.Context) {
reqID := c.MustGet(string(HeaderRequestID)).(string)
ctx, cancel := context.WithCancel(c.Request.Context())
fields := make(map[string]zapcore.Field)
mctx := context.WithValue(ctx, ServiceLogFields, fields)
fctx := context.WithValue(mctx, HeaderRequestID, reqID)
c.Set(ContextKey, fctx)
c.Next()
cancel()
}
}
// GetContext get the context from the gin context
func GetContext(c *gin.Context) context.Context {
return c.MustGet(ContextKey).(context.Context)
}
// ValidateHeaders validates the common headers.
//
// It reports one problem at a time.
func ValidateHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
// It's ok to not specify Content-Type header, but it should be correct if it's specified.
contentType := c.Request.Header.Get(HeaderContentType)
if len(contentType) != 0 {
mType, _, err := mime.ParseMediaType(contentType)
if err != nil {
SetErrorAndAbort(c, UnsupportedMediaType)
return
}
switch mType {
case ContentTypeJSON, ContentTypeOctetStream:
// Passes.
default:
SetErrorAndAbort(c, UnsupportedMediaType)
return
}
}
}
}