feat: update

This commit is contained in:
sujit
2025-08-11 08:38:40 +05:45
parent d514d04cc5
commit da122615fd
6 changed files with 76 additions and 69 deletions

View File

@@ -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",

View 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
}
}
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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)
} }
} }

View File

@@ -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 {