<commit_before>---
title: Schemas
layout: gem-single
name: dry-validation
---

Schemas are a crucial part of `dry-validation`, they pre-process the data before it's validated by [the rules](docs::rules) and can provide detailed error messages. By default, the exposed DSL for defining schemas uses [`dry-schema`](/gems/dry-schema) under the hood.

### Defining a schema without coercion

To define a schema that does not perform coercion, use the `schema` method:

``` ruby
class NewUserContract < Dry::Validation::Contract
  schema do
    required(:email).value(:string)
    required(:age).value(:integer)
  end
end
```

Now when a contract is applied, it will check the structure and types of the input:

``` ruby
contract = NewUserContract.new

result = contract.call(unexpected: :reality, age: 21)
# => #<Dry::Validation::Result{:age=>21} errors={:email=>["is missing"]}>

result.to_h
# => {:age=>21}

result.errors.to_h
# => {:email=>["is missing"]}
```

### Defining a schema with Params coercion

To define a schema suitable for validating HTTP parameters, use the `params` method:

``` ruby
class NewUserContract < Dry::Validation::Contract
  params do
    required(:email).value(:string)
    required(:age).value(:integer)
  end
end
```

The major difference between `params` and the plain `schema` is that `params` latter will perform params-specific coercions before applying the contract's rules. For example, it will coerce strings into integers:

``` ruby
result = contract.call('email' => '<EMAIL>', 'age' => '21')
# => #<Dry::Validation::Result{:email=>"<EMAIL>", :age=>21} errors={}>

result.to_h
# => {:email=>"<EMAIL>", :age=>21}<commit_msg>Typo: remove 'latter'<commit_after>---
title: Schemas
layout: gem-single
name: dry-validation
---

Schemas are a crucial part of `dry-validation`, they pre-process the data before it's validated by [the rules](docs::rules) and can provide detailed error messages. By default, the exposed DSL for defining schemas uses [`dry-schema`](/gems/dry-schema) under the hood.

### Defining a schema without coercion

To define a schema that does not perform coercion, use the `schema` method:

``` ruby
class NewUserContract < Dry::Validation::Contract
  schema do
    required(:email).value(:string)
    required(:age).value(:integer)
  end
end
```

Now when a contract is applied, it will check the structure and types of the input:

``` ruby
contract = NewUserContract.new

result = contract.call(unexpected: :reality, age: 21)
# => #<Dry::Validation::Result{:age=>21} errors={:email=>["is missing"]}>

result.to_h
# => {:age=>21}

result.errors.to_h
# => {:email=>["is missing"]}
```

### Defining a schema with Params coercion

To define a schema suitable for validating HTTP parameters, use the `params` method:

``` ruby
class NewUserContract < Dry::Validation::Contract
  params do
    required(:email).value(:string)
    required(:age).value(:integer)
  end
end
```

The major difference between `params` and the plain `schema` is that `params` will perform params-specific coercions before applying the contract's rules. For example, it will coerce strings into integers:

``` ruby
result = contract.call('email' => '<EMAIL>', 'age' => '21')
# => #<Dry::Validation::Result{:email=>"<EMAIL>", :age=>21} errors={}>

result.to_h
# => {:email=>"<EMAIL>", :age=>21}
{'fraction_non_alphanumeric': 0.14844926227040048, 'fraction_numerical': 0.007226738934056007, 'mean_word_length': 5.174721189591078, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6514880', 'n_tokens_mistral': 1051, 'n_tokens_neox': 977, 'n_words': 348}