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,
- The date time must be in UTC. For example,
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
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.