hashicorp / hashicorp/terraform-plugin-framework-validators

Proposal: Child attribute validators for Objects

Open
#274 0 comments 3 reactions 0 assignees View on GitHub
enhancement
Dominant language
Go
Stars
28
Forks
13
Avg merge
2d 13h
Merged PRs (30d)
1

Description

### Terraform CLI and Framework Versions

All

### Use Cases or Problem Statement

Currently, there isn't a standard method for cleanly validating the child members of an Object. For example, to require exactly one of a set of attributes we need add an `ExactlyOneOf` validator on one of the child attributes, as below. Until #118 is resolved, we also have to add `path.MatchRelative()` as a self-reference.

```go
func (r *resourceBucketLifecycleConfiguration) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) {
response.Schema = schema.Schema{
Version: 1,
Attributes: map[string]schema.Attribute{
// ...
},
Blocks: map[string]schema.Block{
names.AttrRule: schema.ListNestedBlock{
CustomType: fwtypes.NewListNestedObjectTypeOf[lifecycleRuleModel](ctx),
Validators: []validator.List{
listvalidator.SizeAtLeast(1),
},
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
// ...
},
Blocks: map[string]schema.Block{
// ...
"expiration": schema.ListNestedBlock{
CustomType: fwtypes.NewListNestedObjectTypeOf[lifecycleExpirationModel](ctx),
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"date": schema.StringAttribute{
CustomType: timetypes.RFC3339Type{},
Optional: true,
},
"days": schema.Int32Attribute{
Optional: true,
Validators: []validator.Int32{
int32validator.AtLeast(1),
},
},
"expired_object_delete_marker": schema.BoolAttribute{
Optional: true,
Validators: []validator.Bool{
boolvalidator.ExactlyOneOf(
path.MatchRelative(), // Required until #118 is addressed
path.MatchRelative().AtParent().AtName("date"),
path.MatchRelative().AtParent().AtName("days"),
),
},
},
},
},
},
// ...
},
},
},
},
}
}
```

However, the error message displayed is

> No attribute specified when one (and only one) of
[rule[0].expiration[0].expired_object_delete_marker,rule[0].expiration[0].expired_object_delete_marker.<.date,rule[0].expiration[0].expired_object_delete_marker.<.days]

which is hard to read, especially the references to the attributes with the `AtParent` relationship, such as `rule[0].expiration[0].expired_object_delete_marker.<.days`. I would also recommend adding a space after the `,` and possibly demarcate the individual attributes with some form of quotation marks.

Using `objectvalidator.ExactlyOneOf` on the Object includes the object itself in the count, so cannot be used.

### Proposal

Add validators such as `objectvalidator.ExactlyOneOfChildren` which would act like the non-`Children` version but not count itself. For example, in the case above, the following validator would be set on the Object

```go
objectvalidator.ExactlyOneOfChildren(
path.MatchRelative().AtName("date"),
path.MatchRelative().AtName("days"),
path.MatchRelative().AtName("expired_object_delete_marker"),
)
```

### Additional Information

_No response_

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.