mirror of
https://github.com/hhftechnology/middleware-manager.git
synced 2026-07-11 00:48:24 +00:00
86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
package services
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// DecodeArrayOrMap decodes JSON data that can be either an array or a map
|
|
// This is a common pattern in Traefik API responses where the same endpoint
|
|
// can return data in different formats depending on the provider
|
|
//
|
|
// Type parameters:
|
|
// - T: The type of items in the array/map values
|
|
//
|
|
// Returns a slice of items with their names populated from map keys if applicable
|
|
func DecodeArrayOrMap[T any](data []byte, setName func(*T, string)) ([]T, error) {
|
|
// Try array first (more common in newer Traefik versions)
|
|
var items []T
|
|
if err := json.Unmarshal(data, &items); err == nil {
|
|
return items, nil
|
|
}
|
|
|
|
// Try map format (common in older versions or certain providers)
|
|
var itemsMap map[string]T
|
|
if err := json.Unmarshal(data, &itemsMap); err != nil {
|
|
return nil, fmt.Errorf("failed to parse as array or map: %w", err)
|
|
}
|
|
|
|
// Convert map to slice, setting names from keys
|
|
items = make([]T, 0, len(itemsMap))
|
|
for name, item := range itemsMap {
|
|
setName(&item, name)
|
|
items = append(items, item)
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
// DecodeJSONSafe decodes JSON with better error handling
|
|
// Returns the decoded value and any error that occurred
|
|
func DecodeJSONSafe[T any](data []byte) (T, error) {
|
|
var result T
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return result, fmt.Errorf("JSON decode error: %w", err)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// MarshalJSONSafe marshals to JSON with error handling
|
|
func MarshalJSONSafe(v interface{}) ([]byte, error) {
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("JSON encode error: %w", err)
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// ConvertViaJSON converts one struct type to another via JSON marshaling
|
|
// This is useful for converting between similar structs with different types
|
|
func ConvertViaJSON[T any](source interface{}) (*T, error) {
|
|
if source == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
jsonData, err := json.Marshal(source)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal source: %w", err)
|
|
}
|
|
|
|
var result T
|
|
if err := json.Unmarshal(jsonData, &result); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal to target: %w", err)
|
|
}
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
// TryConvertViaJSON is like ConvertViaJSON but returns nil on error instead of an error
|
|
// This is useful when conversion failure is acceptable
|
|
func TryConvertViaJSON[T any](source interface{}) *T {
|
|
result, err := ConvertViaJSON[T](source)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return result
|
|
}
|