# Schemav2Validator Plugin Validates Beckn protocol requests against OpenAPI 3.1 specifications using kin-openapi library. ## Features - Validates requests against OpenAPI 3.1 specs - Supports remote URL and local file loading - Automatic external $ref resolution - TTL-based caching with automatic refresh - Generic path matching (no hardcoded paths) - Direct schema validation without router overhead - Extended schema validation for domain-specific objects with `@context` references ## Configuration ```yaml schemaValidator: id: schemav2validator config: type: url location: https://example.com/openapi-spec.yaml cacheTTL: "3600" extendedSchema_enabled: "true" extendedSchema_cacheTTL: "86400" extendedSchema_maxCacheSize: "100" extendedSchema_downloadTimeout: "30" extendedSchema_allowedDomains: "beckn.org,example.com" ``` ### Configuration Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `type` | string | Yes | - | Type of spec source: "url" or "file" ("dir" reserved for future) | | `location` | string | Yes | - | URL or file path to OpenAPI 3.1 spec | | `cacheTTL` | string | No | "3600" | Cache TTL in seconds before reloading spec | | `extendedSchema_enabled` | string | No | "false" | Enable extended schema validation for `@context` objects | | `extendedSchema_cacheTTL` | string | No | "86400" | Domain schema cache TTL in seconds | | `extendedSchema_maxCacheSize` | string | No | "100" | Maximum number of cached domain schemas | | `extendedSchema_downloadTimeout` | string | No | "30" | Timeout for downloading domain schemas | | `extendedSchema_allowedDomains` | string | No | "" | Comma-separated domain whitelist (empty = all allowed) | ## How It Works ### Initialization (Load Time) **Core Protocol Validation Setup**: 1. **Load OpenAPI Spec**: Loads main spec from `location` (URL or file) with external `$ref` resolution 2. **Build Action Index**: Creates action→schema map for O(1) lookup by scanning all paths/methods 3. **Validate Spec**: Validates OpenAPI spec structure (warnings logged, non-fatal) 4. **Cache Spec**: Stores loaded spec with `loadedAt` timestamp **Extended Schema Setup** (if `extendedSchema_enabled: "true"`): 5. **Initialize Schema Cache**: Creates LRU cache with `maxCacheSize` (default: 100) 6. **Start Background Refresh**: Launches goroutine with two tickers: - Core spec refresh every `cacheTTL` seconds (default: 3600) - Extended schema cleanup every `extendedSchema_cacheTTL` seconds (default: 86400) ### Request Validation (Runtime) **Core Protocol Validation** (always runs): 1. **Parse Request**: Unmarshal JSON and extract `context.action` 2. **Lookup Schema**: O(1) lookup in action index (built at load time) 3. **Validate**: Call `schema.Value.VisitJSON()` with: - Required fields validation - Data type validation (string, number, boolean, object, array) - Format validation (email, uri, date-time, uuid, etc.) - Constraint validation (min/max, pattern, enum, const) - Nested object and array validation 4. **Return Errors**: If validation fails, format and return errors **Extended Schema Validation** (if `extendedSchema_enabled: "true"` AND core validation passed): 5. **Scan for @context**: Recursively traverse `message` field for objects with `@context` and `@type` 6. **Filter Core Schemas**: Skip objects with `/schema/core/` in `@context` URL 7. **Validate Each Domain Object**: - Check domain whitelist (if `allowedDomains` configured) - Transform `@context` URL: `context.jsonld` → `attributes.yaml` - Load schema from URL/file (check cache first, download if miss) - Find schema by `@type` (direct match or `x-jsonld.@type` fallback) - Strip `@context` and `@type` metadata from object - Validate remaining data against domain schema - Prefix error paths with object location (e.g., `message.order.field`) 8. **Return Errors**: Returns first validation error (fail-fast) ## Action-Based Matching The validator uses action-based schema matching, not URL path matching. It searches for schemas where the `context.action` field has an enum constraint containing the request's action value. ### Example OpenAPI Schema ```yaml paths: /beckn/search: post: requestBody: content: application/json: schema: properties: context: properties: action: enum: ["search"] # ← Matches action="search" ``` ### Matching Examples | Request Action | Schema Enum | Match | |----------------|-------------|-------| | `search` | `enum: ["search"]` | ✅ Matches | | `select` | `enum: ["select", "init"]` | ✅ Matches | | `discover` | `enum: ["search"]` | ❌ No match | | `on_search` | `enum: ["on_search"]` | ✅ Matches | ## External References The validator automatically resolves external `$ref` references in OpenAPI specs: ```yaml # Main spec at https://example.com/api.yaml paths: /search: post: requestBody: content: application/json: schema: $ref: 'https://example.com/schemas/search.yaml#/SearchRequest' ``` The loader will automatically fetch and resolve the external reference. ## Example Usage ### Remote URL ```yaml schemaValidator: id: schemav2validator config: type: url location: https://raw.githubusercontent.com/beckn/protocol-specifications/master/api/beckn-2.0.0.yaml cacheTTL: "7200" ``` ### Local File ```yaml schemaValidator: id: schemav2validator config: type: file location: ./validation-scripts/l2-config/mobility_1.1.0_openapi_3.1.yaml cacheTTL: "3600" ``` ### With Extended Schema Validation ```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" extendedSchema_enabled: "true" extendedSchema_cacheTTL: "86400" extendedSchema_maxCacheSize: "100" extendedSchema_downloadTimeout: "30" extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" ``` **At Load Time**: - Creates LRU cache for domain schemas (max 100 entries) - Starts background goroutine for cache cleanup every 24 hours **At Runtime** (after core validation passes): - Scans `message` field for objects with `@context` and `@type` - Skips core Beckn schemas (containing `/schema/core/`) - Downloads domain schemas from `@context` URLs (cached for 24 hours) - Validates domain-specific data against schemas - Returns errors with full JSON paths (e.g., `message.order.chargingRate`) - Fail-fast: returns on first validation error ## Dependencies - `github.com/getkin/kin-openapi` - OpenAPI 3 parser and validator ## Error Messages | Scenario | Error Message | |----------|---------------| | Action is number | `"failed to parse JSON payload: json: cannot unmarshal number into Go struct field .context.action of type string"` | | Action is empty | `"missing field Action in context"` | | Action not in spec | `"unsupported action: "` | | Invalid URL | `"Invalid URL or unreachable: "` | | Schema validation fails | Returns detailed field-level errors |