How to inherit from another Contract

Hi, I tried to find how to extend a contract using inheritance to add a few more fields on top of the parent contract.

Say I have a send_email API endpoint (it’s a contrived example, so there can be some details that may look wrong), and the following contract for that

class SendEmailContract < Dry::Validation::Contract
  params do
    required(:from).filled(:string)
    required(:to).filled(:string)
    required(:text).filled(:string)
  end
end

Then I want to support html email, and want a :html parameter. I want to do something like

class SendHTMLEmailContract < SendEmailContract
  params do
    required(:html).filled(:string)
  end  
end

instead of defining it afresh.

I’ve looked at all the related posts, but a lot of them were for version 0.x, and even in the documentation, I could only find ones involving inheriting a dry-schema from another dry-schema. I want to avoid that because it looks like I have to define both SendEmailSchema and SendEmailContract (which uses the schema to validate), and SendHTMLEmailSchema and SendHTMLEmailContract. Basically two things for every contract.

Is there a support for inheritance for contracts?

This is not yet supported. We’d like to add it in 2.0.0 though. There was an attempt at implementing it but it wasn’t finished.

Thanks! Is there any workaround? Duplicating code for hundreds of contracts will be hard to maintain and prone to error.

Code in your example actually works

dry-validation> SendHTMLEmailContract.new.(from: '1', to: '2', text: '3', html: '4')
=> #<Dry::Validation::Result{:html=>"4", :from=>"1", :to=>"2", :text=>"3"} errors={}>

There are still limitations, though. Inheritance works, but there’s no easy way to compose contracts like in the referenced PR.

@flash-gordon My example was just a made-up syntax. I’m surprised it works, but is there anything you would change in my example to make it more correct (even though it’s a workaround)?
Also, if I’m just planning on using it with inheritance, will this work well enough despite the limitations?