Skip to content

Commit e056822

Browse files
committed
Add documentation for Params extension
Adds documentation for the Params extension to the extensions guide, including: - Overview of input validation with dry-schema - Installation and setup instructions - Basic usage examples showing success and failure cases - Schema class usage for reusing schemas across operations - Integration with custom methods via operate_on - Schema inheritance behavior
1 parent dcbdf8d commit e056822

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed

docsite/source/extensions.html.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,142 @@ end
169169
```
170170

171171
⚠️ Warning: The `:requires_new` option for nested transactions is not yet fully supported.
172+
173+
### Params
174+
175+
The `Params` extension adds input validation support to your operations using [dry-validation](https://dry-rb.org/gems/dry-validation/). When an operation is called, the input will be automatically validated against the defined rules before the operation logic executes. If validation fails, the operation returns a `Failure` with detailed error information without executing the operation body.
176+
177+
Make sure you have dry-validation installed:
178+
179+
```ruby
180+
gem "dry-validation"
181+
```
182+
183+
Require and include the extension in your operation class, then define validation rules using the `params` class method:
184+
185+
```ruby
186+
require "dry/operation/extensions/params"
187+
188+
class CreateUser < Dry::Operation
189+
include Dry::Operation::Extensions::Params
190+
191+
params do
192+
required(:name).filled(:string)
193+
required(:email).filled(:string)
194+
optional(:age).maybe(:integer)
195+
end
196+
197+
def call(input)
198+
user = step create_user(input)
199+
step notify(user)
200+
user
201+
end
202+
203+
# ...
204+
end
205+
```
206+
207+
When validation succeeds, the operation receives the validated and coerced input:
208+
209+
```ruby
210+
result = CreateUser.new.call(name: "Alice", email: "[email protected]", age: "25")
211+
# => Success(user) with age coerced to integer 25
212+
```
213+
214+
When validation fails, the operation returns a `Failure` tagged with `:invalid_params` and the validation errors, without executing any of the operation's steps:
215+
216+
```ruby
217+
result = CreateUser.new.call(name: "", email: "invalid")
218+
# => Failure[:invalid_params, {name: ["must be filled"]}]
219+
```
220+
221+
#### Using params classes
222+
223+
You can also pass a pre-defined params class to `params` instead of a block, which is useful for reusing validation rules across multiple operations:
224+
225+
```ruby
226+
class UserParams < Dry::Operation::Extensions::Params::Params
227+
params do
228+
required(:name).filled(:string)
229+
required(:email).filled(:string)
230+
optional(:age).maybe(:integer)
231+
end
232+
end
233+
234+
class CreateUser < Dry::Operation
235+
include Dry::Operation::Extensions::Params
236+
237+
params UserParams
238+
239+
def call(input)
240+
user = step create_user(input)
241+
step notify(user)
242+
user
243+
end
244+
245+
# ...
246+
end
247+
248+
class UpdateUser < Dry::Operation
249+
include Dry::Operation::Extensions::Params
250+
251+
params UserParams
252+
253+
def call(input)
254+
# ...
255+
end
256+
end
257+
```
258+
259+
#### Using contract for custom validation rules
260+
261+
For more complex validation scenarios, use the `contract` method which provides access to the full dry-validation contract API, including custom rules:
262+
263+
```ruby
264+
class CreateUser < Dry::Operation
265+
include Dry::Operation::Extensions::Params
266+
267+
contract do
268+
params do
269+
required(:name).filled(:string)
270+
required(:age).filled(:integer)
271+
end
272+
273+
rule(:age) do
274+
key.failure("must be 18 or older") if value < 18
275+
end
276+
end
277+
278+
def call(input)
279+
# ...
280+
end
281+
end
282+
```
283+
284+
#### Custom wrapped methods
285+
286+
The `params` extension works seamlessly with custom wrapped methods when using `.operate_on`:
287+
288+
```ruby
289+
class ProcessData < Dry::Operation
290+
include Dry::Operation::Extensions::Params
291+
292+
operate_on :process, :transform
293+
294+
params do
295+
required(:value).filled(:string)
296+
end
297+
298+
def process(input)
299+
input[:value].upcase
300+
end
301+
302+
def transform(input)
303+
input[:value].downcase
304+
end
305+
end
306+
```
307+
308+
#### Inheritance
309+
310+
Params classes are inherited by subclasses, allowing you to build operation hierarchies with shared validation rules.

0 commit comments

Comments
 (0)