bygdata/pkg/devtodev/validation.go

62 lines
1.8 KiB
Go

package devtodev
import "fmt"
// ValidatePayload checks for required fields and common schema errors.
func ValidatePayload(payload Payload) error {
if len(payload.Reports) == 0 {
return fmt.Errorf("reports is required")
}
for ri, report := range payload.Reports {
if report.DeviceID == "" {
return fmt.Errorf("reports[%d].deviceId is required", ri)
}
if len(report.Packages) == 0 {
return fmt.Errorf("reports[%d].packages is required", ri)
}
for pi, pkg := range report.Packages {
events := pkg.Events()
if len(events) == 0 {
return fmt.Errorf("reports[%d].packages[%d].events is required", ri, pi)
}
for ei, event := range events {
if event == nil {
return fmt.Errorf("reports[%d].packages[%d].events[%d] is required", ri, pi, ei)
}
if err := event.Err(); err != nil {
return fmt.Errorf("reports[%d].packages[%d].events[%d] is invalid: %w", ri, pi, ei, err)
}
payload := event.Payload()
code, ok := payload["code"]
if !ok {
return fmt.Errorf("reports[%d].packages[%d].events[%d].code is required", ri, pi, ei)
}
if codeStr, ok := code.(string); !ok || codeStr == "" {
return fmt.Errorf("reports[%d].packages[%d].events[%d].code must be a non-empty string", ri, pi, ei)
}
ts, ok := payload["timestamp"]
if !ok {
return fmt.Errorf("reports[%d].packages[%d].events[%d].timestamp is required", ri, pi, ei)
}
if !isNumber(ts) {
return fmt.Errorf("reports[%d].packages[%d].events[%d].timestamp must be a number", ri, pi, ei)
}
}
}
}
return nil
}
func isNumber(v interface{}) bool {
switch v.(type) {
case int, int8, int16, int32, int64:
return true
case uint, uint8, uint16, uint32, uint64:
return true
case float32, float64:
return true
default:
return false
}
}