We're happy to announce the release of dry-schema 1.5.0! It comes with plenty of new features, fixes, and general improvements. Here are some of the highlights.
Support for composing schemas
You can now compose schemas using logical operators. The only limitation is that xor
is not supported yet as it wasn't clear how error messages are supposed to work. This feature is experimental until we finalize it in version 2.0.0.
In the meantime, please try it out! Here's a simple example:
RoleSchema = Dry::Schema.JSON do
required(:id).filled(:string)
end
ExpirableSchema = Dry::Schema.JSON do
required(:expires_on).value(:date)
end
UserSchema = Dry::Schema.JSON do
required(:name).filled(:string)
required(:role).hash(RoleSchema & ExpirableSchema)
end
UserSchema.(name: "Jane", role: { id: "admin", expires_on: "2020-05-01" }).errors.to_h
# {}
UserSchema.(name: "Jane", role: { id: "", expires_on: "2020-05-01" }).errors.to_h
# {role: {id: ["must be filled"]}}
UserSchema.(name: "Jane", role: { id: "admin", expires_on: "oops" }).errors.to_h
# {role: {expires_on: ["must be a date"]}}
Refer to the documentation for more information.
Errors about unexpected keys
Back in the dry-validation 0.x era, many people asked about returning errors for unexpected keys. Four years later, this feature is finally here! You can enable it with a simple config flag:
UserSchema = Dry::Schema.Params do
# Enable key validation!
config.validate_keys = true
required(:name).filled(:string)
required(:address).hash do
required(:city).filled(:string)
required(:zipcode).filled(:string)
end
required(:roles).array(:hash) do
required(:name).filled(:string)
end
end
input = {
foo: 'unexpected',
name: 'Jane',
address: { bar: 'unexpected', city: 'NYC', zipcode: '1234' },
roles: [{ name: 'admin' }, { name: 'editor', foo: 'unexpected' }]
}
UserSchema.(input).errors.to_h
# {
# :foo=>["is not allowed"],
# :address=>{:bar=>["is not allowed"]},
# :roles=>{1=>{:foo=>["is not allowed"]}}
# }
Notice that it works even for arrays with hashes as elements, which is really nice!
Introspection extension
Another feature request that goes way back is easily seeing which keys are required and which are optional. This is now provided by a new :info
extension, which shows both the keys and their associated types.
To enable it, you need to load the extension:
Dry::Schema.load_extensions(:info)
UserSchema = Dry::Schema.JSON do
required(:email).filled(:string)
optional(:age).filled(:integer)
optional(:address).hash do
required(:street).filled(:string)
required(:zipcode).filled(:string)
required(:city).filled(:string)
end
end
UserSchema.info
# {
# :keys=> {
# :email=>{
# :required=>true,
# :type=>"string"
# },
# :age=>{
# :required=>false,
# :type=>"integer"
# },
# :address=>{
# :type=>"hash",
# :required=>false,
# :keys=>{
# :street=>{
# :required=>true,
# :type=>"string"
# },
# :zipcode=>{
# :required=>true,
# :type=>"string"
# },
# :city=>{
# :required=>true,
# :type=>"string"
# }
# }
# }
# }
# }
Summary
There's way more in the changelog so please check it out and if you're having any issues when upgrading, please do let us know.
Big thanks go to Rob Hanlon and the rest of the contributors who helped with this release!
Last but not least: dry-validation 1.5.0 was released too, which upgrades its own dependency on dry-schema to 1.5.0 and adds a couple of new features.
Please upgrade and enjoy using dry-schema and dry-validation!