diff --git a/validator/validator.go b/validator/validator.go index 41f07b2..f06f5f5 100644 --- a/validator/validator.go +++ b/validator/validator.go @@ -3,6 +3,7 @@ package validator import ( "context" + "encoding/json" "errors" "fmt" "net/url" @@ -160,6 +161,27 @@ func (v *Validator) Validate(ctx context.Context, resource string) error { }) } +// ValidateBytes validates a single STAC resource. +// +// The location is a URL or file path that represents the resource and will +// be used in any validation error. +func ValidateBytes(ctx context.Context, data []byte, location string) error { + resource := crawler.Resource{} + if err := json.Unmarshal(data, &resource); err != nil { + return fmt.Errorf("failed to parse data as JSON: %w", err) + } + v := New(&Options{NoRecursion: true}) + info := &crawler.ResourceInfo{ + Location: location, + Entry: location, + } + err := v.validate(resource, info) + if !errors.Is(err, crawler.ErrStopRecursion) { + return err + } + return nil +} + func (v *Validator) validate(resource crawler.Resource, info *crawler.ResourceInfo) error { v.logger.Info("validating resource", "resource", info.Location) version := resource.Version() diff --git a/validator/validator_test.go b/validator/validator_test.go index 8f7ab84..71f17ec 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -68,6 +68,40 @@ func (s *Suite) TestValidCases() { } } +func (s *Suite) TestValidateBytes() { + cases := []string{ + "v1.0.0-beta.2/LC08_L1TP_097073_20130319_20200913_02_T1.json", + "v1.0.0/catalog.json", + "v1.0.0/collection.json", + "v1.0.0/item.json", + "v1.0.0/catalog-with-item.json", + "v1.0.0/catalog-with-multiple-items.json", + "v1.0.0/item-eo.json", + } + + ctx := context.Background() + for _, c := range cases { + s.Run(c, func() { + location := path.Join("testdata", "cases", c) + data, err := os.ReadFile(location) + s.Require().NoError(err) + s.NoError(validator.ValidateBytes(ctx, data, location)) + }) + } +} + +func (s *Suite) TestValidateBytesInvalidItem() { + location := "testdata/cases/v1.0.0/item-missing-id.json" + + data, readErr := os.ReadFile(location) + s.Require().NoError(readErr) + ctx := context.Background() + + err := validator.ValidateBytes(ctx, data, location) + s.Require().Error(err) + s.Assert().True(strings.HasSuffix(fmt.Sprintf("%#v", err), "missing properties: 'id'")) +} + func (s *Suite) TestSchemaMap() { v := validator.New(&validator.Options{ SchemaMap: map[string]string{