From da122615fd4fcddcd1bd60919f68ad5c85c2057a Mon Sep 17 00:00:00 2001 From: sujit Date: Mon, 11 Aug 2025 08:38:40 +0545 Subject: [PATCH] feat: update --- .../examples/config/policies/apis/sample.json | 19 +------ .../config/policies/schemas/test-route.json | 18 +++++++ services/loader.go | 27 ++++++++++ services/middlewares/schema.go | 14 +---- services/setup.go | 51 ++++++++----------- services/user_config.go | 16 +++--- 6 files changed, 76 insertions(+), 69 deletions(-) create mode 100644 services/examples/config/policies/schemas/test-route.json diff --git a/services/examples/config/policies/apis/sample.json b/services/examples/config/policies/apis/sample.json index 01c1045..9f0df17 100644 --- a/services/examples/config/policies/apis/sample.json +++ b/services/examples/config/policies/apis/sample.json @@ -3,24 +3,7 @@ { "route_uri": "/test-route", "route_method": "POST", - "schema": { - "type": "object", - "description": "users", - "required": [ "user_id" ], - "properties": { - "last_name": { - "type": "string", - "default": "'Baniya'" - }, - "user_id": { - "type": [ - "integer", - "string" - ], - "maxLength": 64 - } - } - }, + "schema_file": "test-route.json", "description": "Handle test route", "model": "test_route", "operation": "custom", diff --git a/services/examples/config/policies/schemas/test-route.json b/services/examples/config/policies/schemas/test-route.json new file mode 100644 index 0000000..076ba1c --- /dev/null +++ b/services/examples/config/policies/schemas/test-route.json @@ -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 + } + } +} \ No newline at end of file diff --git a/services/loader.go b/services/loader.go index 9f13cf6..8bc9d47 100644 --- a/services/loader.go +++ b/services/loader.go @@ -29,6 +29,10 @@ type Loader struct { UserConfig *UserConfig } +var JsonSchemaFunctions = map[string]jsonschema.DefaultFunc{ + "now": jsonschema.DefaultNowFunc, +} + func NewLoader(path string, configFiles ...string) *Loader { var configFile string if len(configFiles) > 0 { @@ -230,6 +234,9 @@ func readSchemas(path string, cfg *UserConfig) error { return err } compiler := jsonschema.NewCompiler() + for name, fn := range JsonSchemaFunctions { + compiler.RegisterDefaultFunc(name, fn) + } for _, entry := range entries { if !entry.IsDir() && isSupportedExt(filepath.Ext(entry.Name())) { file := filepath.Join(path, entry.Name()) @@ -415,6 +422,10 @@ func readApis(path string, cfg *UserConfig) error { if err != nil { return err } + compiler := jsonschema.NewCompiler() + for name, fn := range JsonSchemaFunctions { + compiler.RegisterDefaultFunc(name, fn) + } for _, entry := range entries { if !entry.IsDir() && isSupportedExt(filepath.Ext(entry.Name())) { file := filepath.Join(modelsPath, entry.Name()) @@ -428,6 +439,22 @@ func readApis(path string, cfg *UserConfig) error { return err } 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 handler := cfg.GetHandler(route.HandlerKey); handler != nil { route.Handler = *handler diff --git a/services/middlewares/schema.go b/services/middlewares/schema.go index a5f0d29..03b029c 100644 --- a/services/middlewares/schema.go +++ b/services/middlewares/schema.go @@ -3,8 +3,8 @@ package middlewares import ( "github.com/gofiber/fiber/v2" "github.com/oarkflow/json" + "github.com/oarkflow/jsonschema" "github.com/oarkflow/jsonschema/request" - "github.com/oarkflow/mq/services/utils" ) 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 -func ValidateRequestBySchema(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() - } +func ValidateRequestBySchema(schema *jsonschema.Schema, c *fiber.Ctx) error { body := c.Body() if len(body) == 0 { return c.Next() diff --git a/services/setup.go b/services/setup.go index 4b1367d..6ade7fb 100644 --- a/services/setup.go +++ b/services/setup.go @@ -17,15 +17,15 @@ import ( "github.com/oarkflow/filters" "github.com/oarkflow/form" "github.com/oarkflow/json" - v2 "github.com/oarkflow/jsonschema" "github.com/oarkflow/log" + "github.com/oarkflow/protocol/utils/str" + "github.com/oarkflow/mq" "github.com/oarkflow/mq/consts" "github.com/oarkflow/mq/dag" "github.com/oarkflow/mq/services/http/responses" "github.com/oarkflow/mq/services/middlewares" "github.com/oarkflow/mq/services/utils" - "github.com/oarkflow/protocol/utils/str" ) 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) param := make(map[string]any) query := make(map[string]any) - if route.Schema != nil { - schema := route.GetSchema() - if schema != nil { - if schema.Properties != nil { - for key, property := range *schema.Properties { - if property.In != nil { - for _, in := range property.In { - switch in { - case "param": - param[key] = ctx.Params(key) - case "query": - query[key] = ctx.Query(key) - case "body": - requiredBody[key] = true - } + schema := route.GetSchema() + if schema != nil { + if schema.Properties != nil { + for key, property := range *schema.Properties { + if property.In != nil { + for _, in := range property.In { + switch in { + case "param": + param[key] = ctx.Params(key) + case "query": + query[key] = ctx.Query(key) + case "body": + 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 // against the provided request JSON schema to ensure that the request body is valid. 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 { - if route.Schema == nil { + schema := route.GetSchema() + if schema == nil { return ctx.Next() } requestSchema := ctx.Query("request-schema") @@ -480,11 +469,11 @@ func requestMiddleware(prefix string, route *Route) fiber.Handler { break } } - form, _ := ctx.MultipartForm() - if form != nil { + multipartForm, _ := ctx.MultipartForm() + if multipartForm != nil { return ctx.Next() } - return middlewares.ValidateRequestBySchema(ctx) + return middlewares.ValidateRequestBySchema(schema, ctx) } } diff --git a/services/user_config.go b/services/user_config.go index 954c312..a7713ea 100644 --- a/services/user_config.go +++ b/services/user_config.go @@ -188,14 +188,13 @@ type RestrictedFields struct { } type Route struct { - Name string `json:"name" yaml:"name"` - Description string `json:"description" yaml:"description"` - Uri string `json:"route_uri" yaml:"route_uri"` - HandlerKey string `json:"handler_key" yaml:"handler_key"` - Method string `json:"route_method" yaml:"route_method"` - Schema []byte `json:"schema" yaml:"schema"` - SchemaFile string `json:"schema_file" yaml:"schema_file"` - schema *v2.Schema + Name string `json:"name" yaml:"name"` + Description string `json:"description" yaml:"description"` + Uri string `json:"route_uri" yaml:"route_uri"` + HandlerKey string `json:"handler_key" yaml:"handler_key"` + Method string `json:"route_method" yaml:"route_method"` + Schema []byte `json:"schema" yaml:"schema"` + SchemaFile string `json:"schema_file" yaml:"schema_file"` Rules map[string]string `json:"rules" yaml:"rules"` CustomRules []string `json:"custom_rules" yaml:"custom_rules"` Model string `json:"model" yaml:"model"` @@ -203,6 +202,7 @@ type Route struct { Middlewares []Middleware `json:"middlewares" yaml:"middlewares"` Operation string `json:"operation" yaml:"operation"` RestrictedFields RestrictedFields `json:"restricted_fields" yaml:"restricted_fields"` + schema *v2.Schema } func (r *Route) GetSchema() *v2.Schema {