Custom dry type with multiple constraints

Hi :slight_smile:

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:

  1. 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".
  2. 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?
    # What should be done here?
    # Can I throw some specific DRY exception?
    # If i just return nil, I lose details of the error.

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)
      Failure('date time must be UTC')

def parse(input)
  Success(Time.strptime(input, FORMAT_WITH_MS))
rescue ArgumentError
    Success(Time.strptime(input, FORMAT_WITHOUT_MS))
  rescue ArgumentError
    Failure('date time must be in correct format')

def utc?(time) == 'UTC'

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.


I’d recommend using contract rules for that. Such complex types can be used for coercion purposes but not for validation error messages.