mirror of
https://github.com/oarkflow/mq.git
synced 2025-10-06 00:16:49 +08:00
feat: update
This commit is contained in:
@@ -3,24 +3,7 @@
|
|||||||
{
|
{
|
||||||
"route_uri": "/test-route",
|
"route_uri": "/test-route",
|
||||||
"route_method": "POST",
|
"route_method": "POST",
|
||||||
"schema": {
|
"schema_file": "test-route.json",
|
||||||
"type": "object",
|
|
||||||
"description": "users",
|
|
||||||
"required": [ "user_id" ],
|
|
||||||
"properties": {
|
|
||||||
"last_name": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "'Baniya'"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"type": [
|
|
||||||
"integer",
|
|
||||||
"string"
|
|
||||||
],
|
|
||||||
"maxLength": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"description": "Handle test route",
|
"description": "Handle test route",
|
||||||
"model": "test_route",
|
"model": "test_route",
|
||||||
"operation": "custom",
|
"operation": "custom",
|
||||||
|
18
services/examples/config/policies/schemas/test-route.json
Normal file
18
services/examples/config/policies/schemas/test-route.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"description": "users",
|
||||||
|
"required": [ "user_id" ],
|
||||||
|
"properties": {
|
||||||
|
"last_name": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"maxLength": 64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,10 @@ type Loader struct {
|
|||||||
UserConfig *UserConfig
|
UserConfig *UserConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var JsonSchemaFunctions = map[string]jsonschema.DefaultFunc{
|
||||||
|
"now": jsonschema.DefaultNowFunc,
|
||||||
|
}
|
||||||
|
|
||||||
func NewLoader(path string, configFiles ...string) *Loader {
|
func NewLoader(path string, configFiles ...string) *Loader {
|
||||||
var configFile string
|
var configFile string
|
||||||
if len(configFiles) > 0 {
|
if len(configFiles) > 0 {
|
||||||
@@ -230,6 +234,9 @@ func readSchemas(path string, cfg *UserConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
compiler := jsonschema.NewCompiler()
|
compiler := jsonschema.NewCompiler()
|
||||||
|
for name, fn := range JsonSchemaFunctions {
|
||||||
|
compiler.RegisterDefaultFunc(name, fn)
|
||||||
|
}
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if !entry.IsDir() && isSupportedExt(filepath.Ext(entry.Name())) {
|
if !entry.IsDir() && isSupportedExt(filepath.Ext(entry.Name())) {
|
||||||
file := filepath.Join(path, entry.Name())
|
file := filepath.Join(path, entry.Name())
|
||||||
@@ -415,6 +422,10 @@ func readApis(path string, cfg *UserConfig) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
compiler := jsonschema.NewCompiler()
|
||||||
|
for name, fn := range JsonSchemaFunctions {
|
||||||
|
compiler.RegisterDefaultFunc(name, fn)
|
||||||
|
}
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if !entry.IsDir() && isSupportedExt(filepath.Ext(entry.Name())) {
|
if !entry.IsDir() && isSupportedExt(filepath.Ext(entry.Name())) {
|
||||||
file := filepath.Join(modelsPath, entry.Name())
|
file := filepath.Join(modelsPath, entry.Name())
|
||||||
@@ -428,6 +439,22 @@ func readApis(path string, cfg *UserConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i, route := range api.Routes {
|
for i, route := range api.Routes {
|
||||||
|
if len(route.Schema) > 0 {
|
||||||
|
schema, err := compiler.Compile(route.Schema)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if schema == nil {
|
||||||
|
return errors.New("compiled schema is nil for route: " + route.Uri)
|
||||||
|
}
|
||||||
|
route.schema = schema
|
||||||
|
} else if route.SchemaFile != "" {
|
||||||
|
schema := cfg.GetSchemaInstance(route.SchemaFile)
|
||||||
|
if schema == nil {
|
||||||
|
return errors.New("schema not found for route: " + route.Uri + ", file: " + route.SchemaFile)
|
||||||
|
}
|
||||||
|
route.schema = schema.Instance
|
||||||
|
}
|
||||||
if route.HandlerKey != "" {
|
if route.HandlerKey != "" {
|
||||||
if handler := cfg.GetHandler(route.HandlerKey); handler != nil {
|
if handler := cfg.GetHandler(route.HandlerKey); handler != nil {
|
||||||
route.Handler = *handler
|
route.Handler = *handler
|
||||||
|
@@ -3,8 +3,8 @@ package middlewares
|
|||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/oarkflow/json"
|
"github.com/oarkflow/json"
|
||||||
|
"github.com/oarkflow/jsonschema"
|
||||||
"github.com/oarkflow/jsonschema/request"
|
"github.com/oarkflow/jsonschema/request"
|
||||||
"github.com/oarkflow/mq/services/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ServerApp *fiber.App
|
var ServerApp *fiber.App
|
||||||
@@ -80,17 +80,7 @@ func MatchRouterPath(method, path string) (fiber.Route, bool, map[string]string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRequestBySchema - validates each request that has schema validation
|
// ValidateRequestBySchema - validates each request that has schema validation
|
||||||
func ValidateRequestBySchema(c *fiber.Ctx) error {
|
func ValidateRequestBySchema(schema *jsonschema.Schema, c *fiber.Ctx) error {
|
||||||
route, matched, _ := MatchRouterPath(c.Method(), c.Path())
|
|
||||||
if !matched {
|
|
||||||
return c.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
key := route.Method + ":" + route.Path
|
|
||||||
schema, exists := utils.GetSchema(key)
|
|
||||||
if !exists {
|
|
||||||
return c.Next()
|
|
||||||
}
|
|
||||||
body := c.Body()
|
body := c.Body()
|
||||||
if len(body) == 0 {
|
if len(body) == 0 {
|
||||||
return c.Next()
|
return c.Next()
|
||||||
|
@@ -17,15 +17,15 @@ import (
|
|||||||
"github.com/oarkflow/filters"
|
"github.com/oarkflow/filters"
|
||||||
"github.com/oarkflow/form"
|
"github.com/oarkflow/form"
|
||||||
"github.com/oarkflow/json"
|
"github.com/oarkflow/json"
|
||||||
v2 "github.com/oarkflow/jsonschema"
|
|
||||||
"github.com/oarkflow/log"
|
"github.com/oarkflow/log"
|
||||||
|
"github.com/oarkflow/protocol/utils/str"
|
||||||
|
|
||||||
"github.com/oarkflow/mq"
|
"github.com/oarkflow/mq"
|
||||||
"github.com/oarkflow/mq/consts"
|
"github.com/oarkflow/mq/consts"
|
||||||
"github.com/oarkflow/mq/dag"
|
"github.com/oarkflow/mq/dag"
|
||||||
"github.com/oarkflow/mq/services/http/responses"
|
"github.com/oarkflow/mq/services/http/responses"
|
||||||
"github.com/oarkflow/mq/services/middlewares"
|
"github.com/oarkflow/mq/services/middlewares"
|
||||||
"github.com/oarkflow/mq/services/utils"
|
"github.com/oarkflow/mq/services/utils"
|
||||||
"github.com/oarkflow/protocol/utils/str"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ValidationInstance Validation
|
var ValidationInstance Validation
|
||||||
@@ -341,21 +341,19 @@ func prepareHeader(ctx *fiber.Ctx, route *Route) (map[string]any, map[string]any
|
|||||||
header := make(map[string]any)
|
header := make(map[string]any)
|
||||||
param := make(map[string]any)
|
param := make(map[string]any)
|
||||||
query := make(map[string]any)
|
query := make(map[string]any)
|
||||||
if route.Schema != nil {
|
schema := route.GetSchema()
|
||||||
schema := route.GetSchema()
|
if schema != nil {
|
||||||
if schema != nil {
|
if schema.Properties != nil {
|
||||||
if schema.Properties != nil {
|
for key, property := range *schema.Properties {
|
||||||
for key, property := range *schema.Properties {
|
if property.In != nil {
|
||||||
if property.In != nil {
|
for _, in := range property.In {
|
||||||
for _, in := range property.In {
|
switch in {
|
||||||
switch in {
|
case "param":
|
||||||
case "param":
|
param[key] = ctx.Params(key)
|
||||||
param[key] = ctx.Params(key)
|
case "query":
|
||||||
case "query":
|
query[key] = ctx.Query(key)
|
||||||
query[key] = ctx.Query(key)
|
case "body":
|
||||||
case "body":
|
requiredBody[key] = true
|
||||||
requiredBody[key] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,18 +444,9 @@ func ruleMiddleware(rules map[string]string) fiber.Handler {
|
|||||||
// requestMiddleware validates the request body in the original form of byte array
|
// requestMiddleware validates the request body in the original form of byte array
|
||||||
// against the provided request JSON schema to ensure that the request body is valid.
|
// against the provided request JSON schema to ensure that the request body is valid.
|
||||||
func requestMiddleware(prefix string, route *Route) fiber.Handler {
|
func requestMiddleware(prefix string, route *Route) fiber.Handler {
|
||||||
path := CleanAndMergePaths(prefix, route.Uri)
|
|
||||||
var schema *v2.Schema
|
|
||||||
var err error
|
|
||||||
if route.Schema != nil {
|
|
||||||
schema, err = utils.CompileSchema(path, strings.ToUpper(route.Method), route.Schema)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
route.SetSchema(schema)
|
|
||||||
}
|
|
||||||
return func(ctx *fiber.Ctx) error {
|
return func(ctx *fiber.Ctx) error {
|
||||||
if route.Schema == nil {
|
schema := route.GetSchema()
|
||||||
|
if schema == nil {
|
||||||
return ctx.Next()
|
return ctx.Next()
|
||||||
}
|
}
|
||||||
requestSchema := ctx.Query("request-schema")
|
requestSchema := ctx.Query("request-schema")
|
||||||
@@ -480,11 +469,11 @@ func requestMiddleware(prefix string, route *Route) fiber.Handler {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form, _ := ctx.MultipartForm()
|
multipartForm, _ := ctx.MultipartForm()
|
||||||
if form != nil {
|
if multipartForm != nil {
|
||||||
return ctx.Next()
|
return ctx.Next()
|
||||||
}
|
}
|
||||||
return middlewares.ValidateRequestBySchema(ctx)
|
return middlewares.ValidateRequestBySchema(schema, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -188,14 +188,13 @@ type RestrictedFields struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Name string `json:"name" yaml:"name"`
|
Name string `json:"name" yaml:"name"`
|
||||||
Description string `json:"description" yaml:"description"`
|
Description string `json:"description" yaml:"description"`
|
||||||
Uri string `json:"route_uri" yaml:"route_uri"`
|
Uri string `json:"route_uri" yaml:"route_uri"`
|
||||||
HandlerKey string `json:"handler_key" yaml:"handler_key"`
|
HandlerKey string `json:"handler_key" yaml:"handler_key"`
|
||||||
Method string `json:"route_method" yaml:"route_method"`
|
Method string `json:"route_method" yaml:"route_method"`
|
||||||
Schema []byte `json:"schema" yaml:"schema"`
|
Schema []byte `json:"schema" yaml:"schema"`
|
||||||
SchemaFile string `json:"schema_file" yaml:"schema_file"`
|
SchemaFile string `json:"schema_file" yaml:"schema_file"`
|
||||||
schema *v2.Schema
|
|
||||||
Rules map[string]string `json:"rules" yaml:"rules"`
|
Rules map[string]string `json:"rules" yaml:"rules"`
|
||||||
CustomRules []string `json:"custom_rules" yaml:"custom_rules"`
|
CustomRules []string `json:"custom_rules" yaml:"custom_rules"`
|
||||||
Model string `json:"model" yaml:"model"`
|
Model string `json:"model" yaml:"model"`
|
||||||
@@ -203,6 +202,7 @@ type Route struct {
|
|||||||
Middlewares []Middleware `json:"middlewares" yaml:"middlewares"`
|
Middlewares []Middleware `json:"middlewares" yaml:"middlewares"`
|
||||||
Operation string `json:"operation" yaml:"operation"`
|
Operation string `json:"operation" yaml:"operation"`
|
||||||
RestrictedFields RestrictedFields `json:"restricted_fields" yaml:"restricted_fields"`
|
RestrictedFields RestrictedFields `json:"restricted_fields" yaml:"restricted_fields"`
|
||||||
|
schema *v2.Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Route) GetSchema() *v2.Schema {
|
func (r *Route) GetSchema() *v2.Schema {
|
||||||
|
Reference in New Issue
Block a user