Refactor meshkit/schema to wrap meshery/schemas/validation leaf package
- Dominant language
- Go
- Stars
- 223
- Forks
- 225
- Avg merge
- 7d 1h
- Merged PRs (30d)
- 1
Description
## Context
The `meshery/schemas` repository now has a `validation/` leaf package (`github.com/meshery/schemas/validation`) that owns schema-backed validation using [kin-openapi](https://github.com/getkin/kin-openapi). This is the Phase 0 deliverable from the [validation package design document](https://github.com/meshery/schemas/blob/master/specs/validation-package.md) and [meshery/schemas#624](https://github.com/meshery/schemas/issues/624).
The package is a **dependency-leaf**: it imports `kin-openapi`, `yaml.v3`, and stdlib only. It does NOT import MeshKit or `meshery/schemas/models/...`. This makes it safe for `meshkit/schema` to import without creating cycles.
Currently, `meshkit/schema` owns the full validation implementation — schema loading, compilation, caching, registration, and the validation engine. The design calls for `meshkit/schema` to become a **thin integration layer** that wraps the lower-level engine from `meshery/schemas/validation`, rather than maintaining a separate implementation.
## Current State
### `meshery/schemas/validation` (new — leaf package)
**Package:** `github.com/meshery/schemas/validation`
Currently provides **build-time schema auditing** (41 rules via `go run ./cmd/validate-schemas`). The runtime document validation API is the next addition:
```go
// Planned additions to the leaf package:
func ValidateDocument(data []byte) error
func ValidateWithRef(ref Ref, data []byte) error
func ValidateAny(ref Ref, value any) error
func DecodeAndValidate[T any](data []byte) (T, error)
func ValidationDetailsFromError(err error) (ValidationDetails, bool)
```
These will use `kin-openapi`'s `schema.VisitJSON()` for constraint enforcement, with embedded schema discovery from the `meshery/schemas` module's filesystem.
### `meshkit/schema` (current — full implementation)
**Package:** `github.com/meshery/meshkit/schema`
Full API surface that must be preserved or migrated:
| Category | Functions |
|---|---|
| **Factory** | `Default()`, `New()`, `MustNew()` |
| **Package-level** | `Validate()`, `ValidateWithRef()`, `ValidateAs()`, `DetectRef()` |
| **Generic decode** | `DecodeAndValidate[T]()`, `DecodeAndValidateWithRef[T]()`, `DecodeAndValidateWithValidator[T]()` |
| **Instance methods** | `(*Validator).Validate()`, `.ValidateBytes()`, `.ValidateAny()`, `.Register()` |
| **Error handling** | `ValidationDetailsFromError()`, `ErrValidateDocument()`, etc. |
| **Types** | `Ref`, `Registration`, `Violation`, `ValidationDetails`, `Validator`, `DocumentType` |
## Displacement Plan
### Phase 1: Add runtime validation API to `meshery/schemas/validation`
**Where:** `meshery/schemas` repo
Add these functions to the leaf package, matching the core validation semantics that `meshkit/schema` currently provides:
```go
package validation
// Ref identifies which schema to validate against.
type Ref struct {
SchemaVersion string
Type DocumentType
}
// DocumentType identifies a Meshery document family.
type DocumentType string
const (
TypeComponent DocumentType = "component"
TypeConnection DocumentType = "connection"
TypeDesign DocumentType = "design"
TypeEnvironment DocumentType = "environment"
TypeModel DocumentType = "model"
TypeRelationship DocumentType = "relationship"
TypeWorkspace DocumentType = "workspace"
)
// Violation is a field-level validation failure.
type Violation struct {
InstancePath string
SchemaPath string
Keyword string
Message string
}
// ValidationDetails contains all violations for a rejected document.
type ValidationDetails struct {
Ref Ref
SchemaLocation string
Violations []Violation
}
// ValidateDocument validates bytes against auto-detected schema.
func ValidateDocument(data []byte) error
// ValidateWithRef validates bytes against a specific schema.
func ValidateWithRef(ref Ref, data []byte) error
// ValidateAny validates a Go value against a specific schema.
func ValidateAny(ref Ref, value any) error
// ValidationDetailsFromError extracts structured details from a validation error.
func ValidationDetailsFromError(err error) (ValidationDetails, bool)
```
Key implementation details:
- Schema discovery uses the embedded `meshery/schemas` filesystem (same approach as current `meshkit/schema`)
- Schema compilation uses `kin-openapi` with `singleflight` caching (same pattern)
- `schemaVersion` field detection for auto-ref (same algorithm)
- Returns plain `error` with `ValidationDetails` extractable via `errors.As`
### Phase 2: Refactor `meshkit/schema` to delegate to the leaf package
**Where:** `meshery/meshkit` repo (this issue)
Refactor `meshkit/schema` to:
1. **Import** `github.com/meshery/schemas/validation` as the engine
2. **Delegate** all validation calls to the leaf package
3. **Wrap** leaf package errors into MeshKit `ErrorV2` types
4. **Preserve** the existing `meshkit/schema` public API for backward compatibility
```go
package schema
import (
schemavalidation "github.com/meshery/schemas/validation"
"github.com/meshery/meshkit/errors"
)
// Validate delegates to the leaf package and wraps errors.
func (v *Validator) Validate(data []byte) error {
err := v.leaf.ValidateDocument(data)
if err != nil {
if details, ok := schemavalidation.ValidationDetailsFromError(err); ok {
return ErrValidateDocument(convertDetails(details))
}
return ErrDecodeDocument(err)
}
return nil
}
// ValidateAny delegates to the leaf package.
func (v *Validator) ValidateAny(ref Ref, value any) error {
leafRef := schemavalidation.Ref{
SchemaVersion: ref.SchemaVersion,
Type: schemavalidation.DocumentType(ref.Type),
}
return v.leaf.ValidateAny(leafRef, value)
}
```
What moves **out** of `meshkit/schema`:
- Schema loading, compilation, and caching logic
- `kin-openapi` import and schema visitor calls
- Embedded schema filesystem access
- `singleflight` compilation guard
- Built-in registration discovery
What **stays** in `meshkit/schema`:
- MeshKit-specific error wrapping (`ErrorV2`, error codes `meshkit-11320` through `meshkit-11327`)
- The public API surface (all exported functions and types)
- MeshKit-specific integration patterns (e.g., `DecodeAndValidate[T]` using MeshKit encoding)
### Phase 3: Bump `meshery/schemas` dependency in MeshKit
- Update `go.mod` in meshery/meshkit to the schemas version containing the runtime validation API
- Run `go mod tidy`
- Verify all existing `meshkit/schema` tests pass with the delegation layer
- Verify no API surface changes visible to consumers
## Acceptance Criteria
- [ ] `meshery/schemas/validation` exposes `ValidateDocument`, `ValidateWithRef`, `ValidateAny`, and `ValidationDetailsFromError`
- [ ] `meshkit/schema` imports `meshery/schemas/validation` and delegates all validation calls
- [ ] `meshkit/schema` public API surface is unchanged — no breaking changes for consumers
- [ ] All existing `meshkit/schema` tests pass
- [ ] `kin-openapi` is no longer a direct import in `meshkit/schema` (it comes transitively through the leaf package)
- [ ] Schema compilation caching and singleflight live in the leaf package, not MeshKit
- [ ] MeshKit error wrapping (`ErrorV2` with meshkit error codes) remains in `meshkit/schema`
- [ ] The dependency graph is acyclic: `schemas/validation` → kin-openapi; `meshkit/schema` → `schemas/validation`
## References
- Design document: [meshery/schemas specs/validation-package.md](https://github.com/meshery/schemas/blob/master/specs/validation-package.md)
- Parent issue: [meshery/schemas#624](https://github.com/meshery/schemas/issues/624)
- Original MeshKit PR: meshery/meshkit#932
Contributor guide
Research direction
Start by reading the existing meshkit/schema implementation and its tests, then inspect go.mod and the planned github.com/meshery/schemas/validation API. Trace the current validation, caching, registration, and error-wrapping entry points before assessing the delegation boundaries. Done means the public API and existing meshkit/schema tests remain unchanged while validation ownership moves to the leaf package.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100