-
Notifications
You must be signed in to change notification settings - Fork 89
Description
Smithy4s renders collection types as unwrapped EXCEPT when the collection has been refined 1.
Proposal
Allow to render collection types as wrapped.
Motivation
Currently, users cannot make Smithy4s generate code that enforces the creation of valid collection values at construction time.
Smithy4s already provides a feature that allows validated newtypes for constrained primitives:
As of version 0.18.23 and above, Smithy4s has the ability to render constrained newtypes over Smithy primitives as "validated" classes in the code it generates. In practice, this means that a newtype will now have an apply method that returns either a validated value or an error.
This feature could naturally be extended to collection types.
However, since collections are currently rendered as unwrapped types (e.g. plain List[...]), even if constraints such as @length(min: 1) are defined, constructing a parent object does not require providing a valid collection.
Allowing wrapped collection types would make it possible to leverage the same validation and safety mechanisms that already exist for constrained primitives - ensuring correctness at the point of construction. This is important as currently values are only validated on the deserialization side which is often on the other side of the wire.
Note: Collection types actually always generate newtypes, it is just the code that refers to them that is using their unwrapped variants.
Backward Compatibility
Default behavior remains unchanged - unwrapped collections unless refined.
Codebases upgrading to a version supporting this feature will not break unless they explicitly opt in.
Implementation details
This new behavior should be opt-in both on case-by-case basis with trait as well as globally with a metadata key. When enabled globally it should be possible to opt-out on case-by-case basis with a designated trait.
Opting in on a single case:
@length(min: 1)
@smithy4s.meta#wrap
list Strings {
member: String
}Opting in globally:
Opting in on a single case:
metadata smithy4sRenderWrappedCollections = trueOpting out on a single case when globally opted-in:
@length(min: 1)
@smithy4s.meta#unwrap
list Strings {
member: String
}Additional notes
By introducing via an opt-in flag we can roll out this feature without breaking any generated code but still retain ability to change its default value later if we decided to do so.