Files
yandex-music-api-go/internal/utils/schema.go
T
MrixsandClaude Code 0456ca0665 Add comprehensive godoc documentation to all exported symbols
- Document all exported types, functions, methods, and constants across 52 files
- Add package-level doc comments to client, models, utils, and ynison packages
- Document HTTP method and endpoint path for each API client method
- Document model struct fields and DeJSON/DeList/ToJSON/ToMap methods
- Fix duplicate package doc comment in internal/models/base.go

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-18 08:57:43 +03:00

125 lines
4.3 KiB
Go

// Package utils provides utility functions for the Yandex Music API client,
// including JSON handling, request signing, schema mismatch tracking, and error types.
package utils
import (
"fmt"
"log"
"strings"
"sync"
)
// SchemaMismatch represents a mismatch between expected and actual API response.
// It captures details about missing fields, unknown fields, and unknown values.
type SchemaMismatch struct {
// ModelName is the name of the model that had the mismatch.
ModelName string
// MissingFields lists fields that were expected but not found in the response.
MissingFields []string
// UnknownFields lists fields that were not expected but found in the response.
UnknownFields []string
// UnknownValues maps unknown field names to their values.
UnknownValues map[string]any
// Endpoint is the API endpoint where the mismatch occurred.
Endpoint string
// LibraryVersion is the version of the library when the mismatch occurred.
LibraryVersion string
}
// Describe returns a human-readable description of the schema mismatch.
func (sm *SchemaMismatch) Describe() string {
var parts []string
parts = append(parts, fmt.Sprintf("Model: %s", sm.ModelName))
if len(sm.MissingFields) > 0 {
parts = append(parts, fmt.Sprintf("Missing fields: %v", sm.MissingFields))
}
if len(sm.UnknownFields) > 0 {
parts = append(parts, fmt.Sprintf("Unknown fields: %v", sm.UnknownFields))
}
if len(sm.UnknownValues) > 0 {
parts = append(parts, fmt.Sprintf("Unknown field structures: %v", sm.UnknownValues))
}
parts = append(parts, fmt.Sprintf("Endpoint: %s", sm.Endpoint))
parts = append(parts, fmt.Sprintf("Library version: %s", sm.LibraryVersion))
return strings.Join(parts, "\n")
}
// SchemaMismatchHandler is a callback for handling schema mismatches.
// It is invoked when a schema mismatch is detected, if configured.
type SchemaMismatchHandler func(*SchemaMismatch)
// SchemaMismatchConfig holds configuration for schema mismatch handling.
type SchemaMismatchConfig struct {
// ReportUnknownFields indicates whether unknown fields should be reported.
ReportUnknownFields bool
// Strict indicates whether schema mismatches should be treated as errors.
Strict bool
// OnSchemaMismatch is an optional callback for custom mismatch handling.
OnSchemaMismatch SchemaMismatchHandler
}
// DefaultSchemaMismatchConfig returns the default configuration for schema mismatch handling.
// The default config does not report unknown fields, is not strict, and has no callback.
func DefaultSchemaMismatchConfig() SchemaMismatchConfig {
return SchemaMismatchConfig{
ReportUnknownFields: false,
Strict: false,
OnSchemaMismatch: nil,
}
}
// ReportSchemaMismatch reports a schema mismatch according to the provided config.
// If a callback is configured, it is invoked with the mismatch details.
// If strict mode is enabled, an error is returned. Otherwise, a warning is logged.
func ReportSchemaMismatch(config SchemaMismatchConfig, modelName, endpoint string, missingFields, unknownFields []string, unknownValues map[string]any) error {
mismatch := &SchemaMismatch{
ModelName: modelName,
MissingFields: missingFields,
UnknownFields: unknownFields,
UnknownValues: unknownValues,
Endpoint: endpoint,
LibraryVersion: "go-port-0.1.0",
}
if config.OnSchemaMismatch != nil {
config.OnSchemaMismatch(mismatch)
return nil
}
msg := mismatch.Describe()
if config.Strict {
return fmt.Errorf("schema mismatch: %s", msg)
}
log.Printf("WARNING: Schema mismatch for %s:\n%s", modelName, msg)
return nil
}
// SchemaMismatchTracker tracks reported mismatches to avoid duplicate reports.
// It is safe for concurrent use.
type SchemaMismatchTracker struct {
mu sync.Mutex
reported map[string]bool
}
// NewSchemaMismatchTracker creates a new SchemaMismatchTracker.
func NewSchemaMismatchTracker() *SchemaMismatchTracker {
return &SchemaMismatchTracker{
reported: make(map[string]bool),
}
}
// ShouldReport returns true if the given model and fields have not been reported before.
// It marks them as reported so subsequent calls return false for the same key.
func (t *SchemaMismatchTracker) ShouldReport(modelName string, fields []string) bool {
t.mu.Lock()
defer t.mu.Unlock()
key := modelName + ":" + strings.Join(fields, ",")
if t.reported[key] {
return false
}
t.reported[key] = true
return true
}