Merge pull request #557 from Beckn-One/543-schema2validator
Issue 553 and 554 - Update documentation for schema2validator and improve response readability
This commit is contained in:
41
CONFIG.md
41
CONFIG.md
@@ -479,7 +479,38 @@ schemaValidator:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 5. Sign Validator Plugin
|
#### 5. Schema2Validator Plugin
|
||||||
|
|
||||||
|
**Purpose**: Validate requests against OpenAPI 3.x specifications with action-based matching.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
schemaValidator:
|
||||||
|
id: schemav2validator
|
||||||
|
config:
|
||||||
|
type: url
|
||||||
|
location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/api-specs/beckn-protocol-api.yaml
|
||||||
|
cacheTTL: "3600"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Or for local files:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
schemaValidator:
|
||||||
|
id: schemav2validator
|
||||||
|
config:
|
||||||
|
type: file
|
||||||
|
location: ./validation-scripts/l2-config/mobility_1.1.0_openapi_3.1.yaml
|
||||||
|
cacheTTL: "3600"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `type`: Source type - `"url"` for remote specs, `"file"` for local files
|
||||||
|
- `location`: URL or file path to OpenAPI 3.1 specification
|
||||||
|
- `cacheTTL`: Cache TTL in seconds before reloading spec (default: `"3600"`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 6. Sign Validator Plugin
|
||||||
|
|
||||||
**Purpose**: Validate Ed25519 digital signatures on incoming requests.
|
**Purpose**: Validate Ed25519 digital signatures on incoming requests.
|
||||||
|
|
||||||
@@ -492,7 +523,7 @@ signValidator:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 6. Router Plugin
|
#### 7. Router Plugin
|
||||||
|
|
||||||
**Purpose**: Determine routing destination based on rules.
|
**Purpose**: Determine routing destination based on rules.
|
||||||
|
|
||||||
@@ -517,7 +548,7 @@ router:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 7. Signer Plugin
|
#### 8. Signer Plugin
|
||||||
|
|
||||||
**Purpose**: Sign outgoing requests with Ed25519 signature.
|
**Purpose**: Sign outgoing requests with Ed25519 signature.
|
||||||
|
|
||||||
@@ -530,7 +561,7 @@ signer:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 8. Publisher Plugin
|
#### 9. Publisher Plugin
|
||||||
|
|
||||||
**Purpose**: Publish messages to RabbitMQ or Pub/Sub for asynchronous processing.
|
**Purpose**: Publish messages to RabbitMQ or Pub/Sub for asynchronous processing.
|
||||||
|
|
||||||
@@ -548,7 +579,7 @@ publisher:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 9. Middleware Plugin
|
#### 10. Middleware Plugin
|
||||||
|
|
||||||
**Purpose**: Request preprocessing like UUID generation and header manipulation.
|
**Purpose**: Request preprocessing like UUID generation and header manipulation.
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,8 @@ The **Beckn Protocol** is an open protocol that enables location-aware, local co
|
|||||||
- **Router**: YAML-based routing rules engine for request forwarding
|
- **Router**: YAML-based routing rules engine for request forwarding
|
||||||
- **Signer**: Ed25519 digital signature creation for outgoing requests
|
- **Signer**: Ed25519 digital signature creation for outgoing requests
|
||||||
- **SignValidator**: Ed25519 signature validation for incoming requests
|
- **SignValidator**: Ed25519 signature validation for incoming requests
|
||||||
- **SchemaValidator**: JSON schema validation
|
- **SchemaValidator**: JSON schema validation
|
||||||
|
- **Schemav2Validator**: OpenAPI 3.x schema validation with action-based matching
|
||||||
- **KeyManager**: HashiCorp Vault integration for production key management
|
- **KeyManager**: HashiCorp Vault integration for production key management
|
||||||
- **SimpleKeyManager**: Embedded key management for local development (no external dependencies)
|
- **SimpleKeyManager**: Embedded key management for local development (no external dependencies)
|
||||||
- **Publisher**: RabbitMQ message publishing for asynchronous processing
|
- **Publisher**: RabbitMQ message publishing for asynchronous processing
|
||||||
@@ -305,9 +306,11 @@ modules:
|
|||||||
config:
|
config:
|
||||||
routingConfig: ./config/routing.yaml
|
routingConfig: ./config/routing.yaml
|
||||||
schemaValidator:
|
schemaValidator:
|
||||||
id: schemavalidator
|
id: schemavalidator # or schemav2validator
|
||||||
config:
|
config:
|
||||||
schemaDir: ./schemas
|
schemaDir: ./schemas # for schemavalidator
|
||||||
|
# type: url # for schemav2validator
|
||||||
|
# location: https://example.com/spec.yaml
|
||||||
steps:
|
steps:
|
||||||
- validateSign
|
- validateSign
|
||||||
- addRoute
|
- addRoute
|
||||||
|
|||||||
22
SETUP.md
22
SETUP.md
@@ -830,6 +830,28 @@ schemaValidator:
|
|||||||
schemaURL: https://schemas.beckn.org
|
schemaURL: https://schemas.beckn.org
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Schema2Validator Plugin
|
||||||
|
|
||||||
|
**Remote URL Configuration:**
|
||||||
|
```yaml
|
||||||
|
schemaValidator:
|
||||||
|
id: schemav2validator
|
||||||
|
config:
|
||||||
|
type: url
|
||||||
|
location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/api-specs/beckn-protocol-api.yaml
|
||||||
|
cacheTTL: "3600"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Local File Configuration:**
|
||||||
|
```yaml
|
||||||
|
schemaValidator:
|
||||||
|
id: schemav2validator
|
||||||
|
config:
|
||||||
|
type: file
|
||||||
|
location: ./schemas/beckn-protocol-api.yaml
|
||||||
|
cacheTTL: "3600"
|
||||||
|
```
|
||||||
|
|
||||||
#### Router Plugin
|
#### Router Plugin
|
||||||
```yaml
|
```yaml
|
||||||
router:
|
router:
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ func (v *schemav2Validator) Validate(ctx context.Context, reqURL *url.URL, data
|
|||||||
|
|
||||||
opts := []openapi3.SchemaValidationOption{
|
opts := []openapi3.SchemaValidationOption{
|
||||||
openapi3.VisitAsRequest(),
|
openapi3.VisitAsRequest(),
|
||||||
openapi3.MultiErrors(),
|
|
||||||
openapi3.EnableFormatValidation(),
|
openapi3.EnableFormatValidation(),
|
||||||
}
|
}
|
||||||
if err := schema.Value.VisitJSON(jsonData, opts...); err != nil {
|
if err := schema.Value.VisitJSON(jsonData, opts...); err != nil {
|
||||||
@@ -233,21 +232,39 @@ func (v *schemav2Validator) formatValidationError(err error) error {
|
|||||||
// extractSchemaErrors recursively extracts detailed error information from SchemaError.
|
// extractSchemaErrors recursively extracts detailed error information from SchemaError.
|
||||||
func (v *schemav2Validator) extractSchemaErrors(err error, schemaErrors *[]model.Error) {
|
func (v *schemav2Validator) extractSchemaErrors(err error, schemaErrors *[]model.Error) {
|
||||||
if schemaErr, ok := err.(*openapi3.SchemaError); ok {
|
if schemaErr, ok := err.(*openapi3.SchemaError); ok {
|
||||||
// If there's an origin error, recursively extract from it
|
// Extract path from current error and message from Origin if available
|
||||||
if schemaErr.Origin != nil {
|
pathParts := schemaErr.JSONPointer()
|
||||||
v.extractSchemaErrors(schemaErr.Origin, schemaErrors)
|
path := strings.Join(pathParts, "/")
|
||||||
} else {
|
if path == "" {
|
||||||
// Leaf error - extract the actual validation failure
|
path = schemaErr.SchemaField
|
||||||
pathParts := schemaErr.JSONPointer()
|
|
||||||
path := strings.Join(pathParts, "/")
|
|
||||||
if path == "" {
|
|
||||||
path = schemaErr.SchemaField
|
|
||||||
}
|
|
||||||
*schemaErrors = append(*schemaErrors, model.Error{
|
|
||||||
Paths: path,
|
|
||||||
Message: schemaErr.Reason,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message := schemaErr.Reason
|
||||||
|
if schemaErr.Origin != nil {
|
||||||
|
originMsg := schemaErr.Origin.Error()
|
||||||
|
// Extract specific field error from nested message
|
||||||
|
if strings.Contains(originMsg, "Error at \"/") {
|
||||||
|
// Find last "Error at" which has the specific field error
|
||||||
|
parts := strings.Split(originMsg, "Error at \"")
|
||||||
|
if len(parts) > 1 {
|
||||||
|
lastPart := parts[len(parts)-1]
|
||||||
|
// Extract field path and update both path and message
|
||||||
|
if idx := strings.Index(lastPart, "\":"); idx > 0 {
|
||||||
|
fieldPath := lastPart[:idx]
|
||||||
|
fieldMsg := strings.TrimSpace(lastPart[idx+2:])
|
||||||
|
path = strings.TrimPrefix(fieldPath, "/")
|
||||||
|
message = fieldMsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message = originMsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*schemaErrors = append(*schemaErrors, model.Error{
|
||||||
|
Paths: path,
|
||||||
|
Message: message,
|
||||||
|
})
|
||||||
} else if multiErr, ok := err.(openapi3.MultiError); ok {
|
} else if multiErr, ok := err.(openapi3.MultiError); ok {
|
||||||
// Nested MultiError
|
// Nested MultiError
|
||||||
for _, e := range multiErr {
|
for _, e := range multiErr {
|
||||||
|
|||||||
Reference in New Issue
Block a user