Hi
I was just wondering the best way to define a custom dry type with some constraints, and then use it in a dry contract?
For example, let’s say we wanted a custom Time type which was constructed from a string. This type would fail to be created if it didn’t meet the following constraints:
- The input string must be in an ISO8601 format like
"2019-01-11T01:12:34Z"
. It could also optionally include milliseconds For example,"2019-01-11T01:12:34.567Z"
. - The date time must be in UTC. For example,
"2019-01-11T01:12:34+11:00"
would fail.
Just looking at the documentation, I was unsure how to implement this. If we follow an example from the custom types constructor docs, I’m not sure exactly how to return meaningful errors from a custom constructor. There would be errors unique to each specific constraint, for example if the input string was in a valid format, but, was not in UTC.
Some example code to demonstrate my problem.
CustomTime = Types.Constructor(Types::Strict::Time) do |value|
result = construct(value.to_s)
if value.success?
result.value!
else
# What should be done here?
# Can I throw some specific DRY exception?
# If i just return nil, I lose details of the error.
end
end
FORMAT_WITH_MS = '%Y-%m-%dT%H:%M:%S.%L%z'.freeze
FORMAT_WITHOUT_MS = '%Y-%m-%dT%H:%M:%S%z'.freeze
def construct(input)
parse(input).bind do |time|
if utc?(time)
Success(time)
else
Failure('date time must be UTC')
end
end
end
def parse(input)
Success(Time.strptime(input, FORMAT_WITH_MS))
rescue ArgumentError
begin
Success(Time.strptime(input, FORMAT_WITHOUT_MS))
rescue ArgumentError
Failure('date time must be in correct format')
end
end
def utc?(time)
time.zone == 'UTC'
end
If the CustomTime
type was used in a dry contract to validate some HTTP request payload which contained an invalid date time, I’d like for the specific time related error to be returned in the result from calling the contract.
Please let me know If I’m going about this completely wrong. I’m new to the dry gems, so would love the opinion of a contributor or experienced user on the best way forward in a situation like this.
Thanks!