cmdx 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cursor/prompts/docs.md +9 -0
- data/.cursor/prompts/rspec.md +13 -12
- data/.cursor/prompts/yardoc.md +11 -6
- data/CHANGELOG.md +13 -2
- data/README.md +1 -0
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +124 -58
- data/docs/basics/chain.md +190 -160
- data/docs/basics/context.md +242 -154
- data/docs/basics/setup.md +302 -32
- data/docs/callbacks.md +390 -94
- data/docs/configuration.md +181 -65
- data/docs/deprecation.md +245 -0
- data/docs/getting_started.md +161 -39
- data/docs/internationalization.md +590 -70
- data/docs/interruptions/exceptions.md +135 -118
- data/docs/interruptions/faults.md +150 -125
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +181 -118
- data/docs/middlewares.md +150 -377
- data/docs/outcomes/result.md +140 -112
- data/docs/outcomes/states.md +134 -99
- data/docs/outcomes/statuses.md +204 -146
- data/docs/parameters/coercions.md +232 -281
- data/docs/parameters/defaults.md +224 -169
- data/docs/parameters/definitions.md +289 -141
- data/docs/parameters/namespacing.md +250 -161
- data/docs/parameters/validations.md +260 -133
- data/docs/testing.md +191 -197
- data/docs/workflows.md +143 -98
- data/lib/cmdx/callback.rb +23 -19
- data/lib/cmdx/callback_registry.rb +1 -3
- data/lib/cmdx/chain_inspector.rb +23 -23
- data/lib/cmdx/chain_serializer.rb +38 -19
- data/lib/cmdx/coercion.rb +20 -12
- data/lib/cmdx/coercion_registry.rb +51 -32
- data/lib/cmdx/configuration.rb +84 -31
- data/lib/cmdx/context.rb +32 -21
- data/lib/cmdx/core_ext/hash.rb +13 -13
- data/lib/cmdx/core_ext/module.rb +1 -1
- data/lib/cmdx/core_ext/object.rb +12 -12
- data/lib/cmdx/correlator.rb +60 -39
- data/lib/cmdx/errors.rb +105 -131
- data/lib/cmdx/fault.rb +66 -45
- data/lib/cmdx/immutator.rb +20 -21
- data/lib/cmdx/lazy_struct.rb +78 -70
- data/lib/cmdx/log_formatters/json.rb +1 -1
- data/lib/cmdx/log_formatters/key_value.rb +1 -1
- data/lib/cmdx/log_formatters/line.rb +1 -1
- data/lib/cmdx/log_formatters/logstash.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
- data/lib/cmdx/log_formatters/raw.rb +2 -2
- data/lib/cmdx/logger.rb +19 -14
- data/lib/cmdx/logger_ansi.rb +33 -17
- data/lib/cmdx/logger_serializer.rb +85 -24
- data/lib/cmdx/middleware.rb +39 -21
- data/lib/cmdx/middleware_registry.rb +4 -3
- data/lib/cmdx/parameter.rb +151 -89
- data/lib/cmdx/parameter_inspector.rb +34 -21
- data/lib/cmdx/parameter_registry.rb +36 -30
- data/lib/cmdx/parameter_serializer.rb +21 -14
- data/lib/cmdx/result.rb +136 -135
- data/lib/cmdx/result_ansi.rb +31 -17
- data/lib/cmdx/result_inspector.rb +32 -27
- data/lib/cmdx/result_logger.rb +23 -14
- data/lib/cmdx/result_serializer.rb +65 -27
- data/lib/cmdx/task.rb +234 -113
- data/lib/cmdx/task_deprecator.rb +22 -25
- data/lib/cmdx/task_processor.rb +89 -88
- data/lib/cmdx/task_serializer.rb +27 -14
- data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
- data/lib/cmdx/validator.rb +25 -16
- data/lib/cmdx/validator_registry.rb +53 -31
- data/lib/cmdx/validators/exclusion.rb +1 -1
- data/lib/cmdx/validators/format.rb +2 -2
- data/lib/cmdx/validators/inclusion.rb +2 -2
- data/lib/cmdx/validators/length.rb +2 -2
- data/lib/cmdx/validators/numeric.rb +3 -3
- data/lib/cmdx/validators/presence.rb +2 -2
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +54 -33
- data/lib/generators/cmdx/task_generator.rb +6 -6
- data/lib/generators/cmdx/workflow_generator.rb +6 -6
- metadata +3 -1
@@ -1,60 +1,91 @@
|
|
1
1
|
# Parameters - Definitions
|
2
2
|
|
3
|
-
Parameters
|
3
|
+
Parameters define the interface between task callers and implementation, enabling automatic validation, type coercion, and method generation. They provide a contract to verify that task execution arguments match expected requirements and structure.
|
4
4
|
|
5
5
|
## Table of Contents
|
6
6
|
|
7
7
|
- [TLDR](#tldr)
|
8
|
-
- [Parameter
|
8
|
+
- [Basic Parameter Definition](#basic-parameter-definition)
|
9
9
|
- [Parameter Sources](#parameter-sources)
|
10
10
|
- [Nested Parameters](#nested-parameters)
|
11
|
-
- [
|
11
|
+
- [Advanced Features](#advanced-features)
|
12
12
|
- [Error Handling](#error-handling)
|
13
13
|
|
14
14
|
## TLDR
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- **Call interface** - Parameters passed as keyword arguments to `TaskClass.call(param: value)`
|
16
|
+
```ruby
|
17
|
+
class ProcessOrderTask < CMDx::Task
|
18
|
+
# Required parameters - must be provided
|
19
|
+
required :order_id, :customer_id
|
21
20
|
|
22
|
-
|
21
|
+
# Optional parameters - can be nil
|
22
|
+
optional :notes, :priority
|
23
23
|
|
24
|
-
|
24
|
+
# Custom sources
|
25
|
+
required :name, :email, source: :user
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
# Nested parameters
|
28
|
+
required :shipping_address do
|
29
|
+
required :street, :city, :state
|
30
|
+
optional :apartment
|
31
|
+
end
|
28
32
|
|
29
|
-
|
33
|
+
def call
|
34
|
+
order_id # → value from call arguments
|
35
|
+
name # → delegates to user.name
|
36
|
+
street # → delegates to shipping_address.street
|
37
|
+
end
|
38
|
+
end
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
40
|
+
# Usage
|
41
|
+
ProcessOrderTask.call(
|
42
|
+
order_id: 123,
|
43
|
+
customer_id: 456,
|
44
|
+
shipping_address: { street: "123 Main St", city: "Miami", state: "FL" }
|
45
|
+
)
|
46
|
+
```
|
35
47
|
|
36
|
-
|
37
|
-
|
48
|
+
## Basic Parameter Definition
|
49
|
+
|
50
|
+
> [!IMPORTANT]
|
51
|
+
> Required parameters must be provided in call arguments or task execution will fail. Optional parameters return `nil` when not provided.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class CreateUserTask < CMDx::Task
|
55
|
+
# Single parameter definitions
|
56
|
+
required :email
|
57
|
+
optional :name
|
38
58
|
|
39
59
|
# Multiple parameters in one declaration
|
40
|
-
required :
|
41
|
-
optional :
|
60
|
+
required :age, :phone
|
61
|
+
optional :bio, :website
|
62
|
+
|
63
|
+
# Parameters with type coercion and validation
|
64
|
+
required :age, type: :integer, numeric: { min: 18 }
|
65
|
+
optional :tags, type: :array, default: []
|
42
66
|
|
43
67
|
def call
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
68
|
+
# All parameters become instance methods
|
69
|
+
user = User.create!(
|
70
|
+
email: email, # Required - guaranteed to be present
|
71
|
+
name: name, # Optional - may be nil
|
72
|
+
age: age, # Required integer, validated >= 18
|
73
|
+
phone: phone, # Required - guaranteed to be present
|
74
|
+
bio: bio, # Optional - may be nil
|
75
|
+
tags: tags # Optional array with default []
|
76
|
+
)
|
77
|
+
|
78
|
+
user
|
48
79
|
end
|
49
80
|
end
|
50
81
|
|
51
82
|
# Parameters passed as keyword arguments
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
83
|
+
CreateUserTask.call(
|
84
|
+
email: "user@example.com",
|
85
|
+
age: 25,
|
86
|
+
phone: "555-0123",
|
87
|
+
name: "John Doe",
|
88
|
+
tags: ["premium", "beta"]
|
58
89
|
)
|
59
90
|
```
|
60
91
|
|
@@ -62,42 +93,49 @@ CreateOrderTask.call(
|
|
62
93
|
|
63
94
|
Parameters delegate to source objects within the task context. The default source is `:context`, but any accessible method or object can serve as a parameter source.
|
64
95
|
|
96
|
+
> [!NOTE]
|
97
|
+
> Sources allow parameters to pull values from different objects instead of just call arguments.
|
98
|
+
|
65
99
|
### Default Context Source
|
66
100
|
|
67
101
|
```ruby
|
68
|
-
class
|
69
|
-
#
|
102
|
+
class UpdateProfileTask < CMDx::Task
|
103
|
+
# Default source is :context
|
70
104
|
required :user_id
|
105
|
+
optional :avatar_url
|
71
106
|
|
72
|
-
# Explicitly
|
107
|
+
# Explicitly specify context source
|
73
108
|
required :email, source: :context
|
74
109
|
|
75
110
|
def call
|
76
|
-
|
77
|
-
|
111
|
+
user = User.find(user_id) # From context.user_id
|
112
|
+
user.update!(
|
113
|
+
email: email, # From context.email
|
114
|
+
avatar_url: avatar_url # From context.avatar_url
|
115
|
+
)
|
78
116
|
end
|
79
117
|
end
|
80
|
-
|
81
|
-
UpdateUserTask.call(user_id: 123, email: "user@example.com")
|
82
118
|
```
|
83
119
|
|
84
120
|
### Custom Object Sources
|
85
121
|
|
86
122
|
```ruby
|
87
|
-
class
|
123
|
+
class GenerateInvoiceTask < CMDx::Task
|
88
124
|
# Delegate to user object
|
89
125
|
required :name, :email, source: :user
|
90
126
|
|
91
127
|
# Delegate to order object
|
92
|
-
required :total, :
|
128
|
+
required :total, :items, source: :order
|
93
129
|
optional :discount, source: :order
|
94
130
|
|
95
131
|
def call
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
132
|
+
Invoice.create!(
|
133
|
+
customer_name: name, # From user.name
|
134
|
+
customer_email: email, # From user.email
|
135
|
+
amount: total, # From order.total
|
136
|
+
line_items: items, # From order.items
|
137
|
+
discount_amount: discount # From order.discount
|
138
|
+
)
|
101
139
|
end
|
102
140
|
|
103
141
|
private
|
@@ -111,187 +149,297 @@ class ProcessUserOrderTask < CMDx::Task
|
|
111
149
|
end
|
112
150
|
end
|
113
151
|
|
114
|
-
|
152
|
+
GenerateInvoiceTask.call(user_id: 123, order_id: 456)
|
115
153
|
```
|
116
154
|
|
117
155
|
### Dynamic Sources
|
118
156
|
|
119
157
|
```ruby
|
120
|
-
class
|
121
|
-
# Lambda source for dynamic resolution
|
122
|
-
required :
|
158
|
+
class CalculatePermissionsTask < CMDx::Task
|
159
|
+
# Proc/Lambda source for dynamic resolution
|
160
|
+
required :current_user, source: ->(task) { User.find(task.context.user_id) }
|
161
|
+
required :company_name, source: proc { Company.find_by(context.company_id).name }
|
123
162
|
|
124
|
-
# Method
|
125
|
-
required :
|
163
|
+
# Method symbol sources
|
164
|
+
required :role, source: :determine_user_role
|
126
165
|
optional :access_level, source: :calculate_access_level
|
127
166
|
|
128
167
|
def call
|
129
|
-
|
130
|
-
|
131
|
-
|
168
|
+
{
|
169
|
+
user: current_user.name, # Resolved via lambda
|
170
|
+
company: company_name, # Resolved via proc
|
171
|
+
role: role, # From determine_user_role method
|
172
|
+
access: access_level # From calculate_access_level method
|
173
|
+
}
|
132
174
|
end
|
133
175
|
|
134
176
|
private
|
135
177
|
|
136
|
-
def
|
137
|
-
|
138
|
-
end
|
139
|
-
|
140
|
-
def determine_account_type
|
141
|
-
user.premium? ? "premium" : "standard"
|
178
|
+
def determine_user_role
|
179
|
+
current_user.admin? ? "admin" : "user"
|
142
180
|
end
|
143
181
|
|
144
182
|
def calculate_access_level
|
145
|
-
|
183
|
+
case role
|
184
|
+
when "admin" then "full"
|
185
|
+
when "user" then "limited"
|
186
|
+
else "none"
|
187
|
+
end
|
146
188
|
end
|
147
189
|
end
|
148
190
|
```
|
149
191
|
|
150
192
|
## Nested Parameters
|
151
193
|
|
152
|
-
Nested parameters
|
153
|
-
|
154
|
-
> [!NOTE]
|
155
|
-
> Child parameters are only required when their parent parameter is provided.
|
194
|
+
Nested parameters enable complex parameter structures where child parameters automatically inherit their parent as the source. This allows validation and access of structured data.
|
156
195
|
|
157
|
-
|
196
|
+
> [!TIP]
|
197
|
+
> Child parameters are only required when their parent parameter is provided, enabling flexible optional structures.
|
158
198
|
|
159
199
|
```ruby
|
160
|
-
class
|
161
|
-
|
200
|
+
class CreateShipmentTask < CMDx::Task
|
201
|
+
required :order_id
|
202
|
+
|
203
|
+
# Required parent with required children
|
162
204
|
required :shipping_address do
|
163
|
-
required :street, :city, :state, :
|
164
|
-
optional :
|
205
|
+
required :street, :city, :state, :zip
|
206
|
+
optional :apartment, :instructions
|
165
207
|
end
|
166
208
|
|
167
|
-
# Optional parent with
|
209
|
+
# Optional parent with conditional children
|
168
210
|
optional :billing_address do
|
169
|
-
required :street, :city
|
211
|
+
required :street, :city # Only required if billing_address provided
|
170
212
|
optional :same_as_shipping
|
171
213
|
end
|
172
214
|
|
215
|
+
# Multi-level nesting
|
216
|
+
optional :special_handling do
|
217
|
+
required :type
|
218
|
+
|
219
|
+
optional :insurance do
|
220
|
+
required :coverage_amount, type: :float
|
221
|
+
optional :carrier
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
173
225
|
def call
|
174
|
-
|
175
|
-
|
226
|
+
shipment = Shipment.create!(
|
227
|
+
order_id: order_id,
|
228
|
+
|
229
|
+
# Access nested parameters directly
|
230
|
+
ship_to_street: street, # From shipping_address.street
|
231
|
+
ship_to_city: city, # From shipping_address.city
|
232
|
+
ship_to_state: state, # From shipping_address.state
|
233
|
+
delivery_instructions: instructions,
|
176
234
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
235
|
+
# Handle optional nested structures
|
236
|
+
special_handling_type: type, # From special_handling.type (if provided)
|
237
|
+
insurance_amount: coverage_amount # From special_handling.insurance.coverage_amount
|
238
|
+
)
|
239
|
+
|
240
|
+
shipment
|
181
241
|
end
|
182
242
|
end
|
183
243
|
|
184
|
-
|
244
|
+
CreateShipmentTask.call(
|
245
|
+
order_id: 123,
|
185
246
|
shipping_address: {
|
186
247
|
street: "123 Main St",
|
187
248
|
city: "Miami",
|
188
249
|
state: "FL",
|
189
|
-
|
250
|
+
zip: "33101",
|
251
|
+
instructions: "Leave at door"
|
252
|
+
},
|
253
|
+
special_handling: {
|
254
|
+
type: "fragile",
|
255
|
+
insurance: {
|
256
|
+
coverage_amount: 500.00,
|
257
|
+
carrier: "FedEx"
|
258
|
+
}
|
190
259
|
}
|
191
260
|
)
|
192
261
|
```
|
193
262
|
|
194
|
-
|
263
|
+
## Advanced Features
|
264
|
+
|
265
|
+
### Parameter Method Generation
|
195
266
|
|
196
267
|
```ruby
|
197
|
-
class
|
198
|
-
required :
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
end
|
268
|
+
class ProcessPaymentTask < CMDx::Task
|
269
|
+
required :amount, type: :float
|
270
|
+
required :payment_method
|
271
|
+
|
272
|
+
# Nested parameters generate flattened methods
|
273
|
+
required :customer do
|
274
|
+
required :id, :email
|
275
|
+
|
276
|
+
optional :billing_address do
|
277
|
+
required :street, :city
|
278
|
+
optional :unit
|
209
279
|
end
|
210
280
|
end
|
211
281
|
|
212
282
|
def call
|
213
|
-
#
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
283
|
+
# All parameters accessible as instance methods
|
284
|
+
payment = PaymentService.charge(
|
285
|
+
amount: amount, # Direct parameter access
|
286
|
+
method: payment_method, # Direct parameter access
|
287
|
+
customer_id: id, # From customer.id
|
288
|
+
customer_email: email, # From customer.email
|
289
|
+
billing_street: street, # From customer.billing_address.street
|
290
|
+
billing_city: city # From customer.billing_address.city
|
291
|
+
)
|
292
|
+
|
293
|
+
payment
|
218
294
|
end
|
219
295
|
end
|
220
296
|
```
|
221
297
|
|
222
|
-
|
298
|
+
### Parameter Introspection
|
223
299
|
|
224
|
-
|
300
|
+
```ruby
|
301
|
+
class IntrospectionExampleTask < CMDx::Task
|
302
|
+
required :name
|
303
|
+
optional :age, type: :integer, default: 18
|
225
304
|
|
226
|
-
|
227
|
-
|
305
|
+
required :address do
|
306
|
+
required :street
|
307
|
+
optional :unit
|
308
|
+
end
|
228
309
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
310
|
+
def call
|
311
|
+
# Access parameter metadata
|
312
|
+
params = self.class.parameters
|
313
|
+
|
314
|
+
params.each do |param|
|
315
|
+
puts "Parameter: #{param.name}"
|
316
|
+
puts "Required: #{param.required?}"
|
317
|
+
puts "Type: #{param.type}"
|
318
|
+
puts "Default: #{param.default}" if param.has_default?
|
319
|
+
puts "Source: #{param.source}"
|
320
|
+
puts "---"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
```
|
233
325
|
|
234
|
-
|
235
|
-
|
326
|
+
## Error Handling
|
327
|
+
|
328
|
+
> [!WARNING]
|
329
|
+
> Parameter validation failures result in structured error information with details about each failed parameter.
|
236
330
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
331
|
+
### Missing Required Parameters
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
class RequiredParamsTask < CMDx::Task
|
335
|
+
required :user_id, :order_id
|
336
|
+
required :shipping_address do
|
337
|
+
required :street, :city
|
241
338
|
end
|
242
339
|
|
243
340
|
def call
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
341
|
+
# Task logic
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
# Missing required parameters
|
346
|
+
result = RequiredParamsTask.call(user_id: 123)
|
347
|
+
result.failed? # → true
|
348
|
+
result.metadata
|
349
|
+
# {
|
350
|
+
# reason: "order_id is required. shipping_address is required.",
|
351
|
+
# messages: {
|
352
|
+
# order_id: ["is required"],
|
353
|
+
# shipping_address: ["is required"]
|
354
|
+
# }
|
355
|
+
# }
|
356
|
+
|
357
|
+
# Missing nested required parameters
|
358
|
+
result = RequiredParamsTask.call(
|
359
|
+
user_id: 123,
|
360
|
+
order_id: 456,
|
361
|
+
shipping_address: { street: "123 Main St" } # Missing city
|
362
|
+
)
|
363
|
+
result.failed? # → true
|
364
|
+
result.metadata
|
365
|
+
# {
|
366
|
+
# reason: "city is required.",
|
367
|
+
# messages: {
|
368
|
+
# city: ["is required"]
|
369
|
+
# }
|
370
|
+
# }
|
371
|
+
```
|
372
|
+
|
373
|
+
### Source Resolution Errors
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
class SourceErrorTask < CMDx::Task
|
377
|
+
required :name, source: :user
|
378
|
+
required :status, source: :nonexistent_method
|
379
|
+
|
380
|
+
def call
|
381
|
+
# Task logic
|
248
382
|
end
|
249
383
|
|
250
384
|
private
|
251
385
|
|
252
|
-
def
|
253
|
-
|
386
|
+
def user
|
387
|
+
# This will raise an error
|
388
|
+
raise StandardError, "User service unavailable"
|
254
389
|
end
|
255
390
|
end
|
256
|
-
```
|
257
|
-
|
258
|
-
## Error Handling
|
259
391
|
|
260
|
-
|
392
|
+
result = SourceErrorTask.call
|
393
|
+
result.failed? # → true
|
394
|
+
# Error propagated from source resolution failure
|
395
|
+
```
|
261
396
|
|
262
|
-
|
263
|
-
> Invalid parameters will cause task execution to fail with detailed error messages.
|
397
|
+
### Complex Validation Errors
|
264
398
|
|
265
399
|
```ruby
|
266
|
-
class
|
400
|
+
class ValidationErrorTask < CMDx::Task
|
401
|
+
required :email, format: { with: /@/ }
|
267
402
|
required :age, type: :integer, numeric: { min: 18, max: 120 }
|
268
|
-
|
269
|
-
|
403
|
+
optional :phone, format: { with: /\A\d{10}\z/ }
|
404
|
+
|
405
|
+
required :preferences do
|
406
|
+
required :theme, inclusion: { in: %w[light dark] }
|
407
|
+
optional :language, inclusion: { in: %w[en es fr] }
|
408
|
+
end
|
270
409
|
|
271
410
|
def call
|
272
|
-
# Task logic
|
411
|
+
# Task logic
|
273
412
|
end
|
274
413
|
end
|
275
414
|
|
276
|
-
#
|
277
|
-
result =
|
278
|
-
|
279
|
-
|
280
|
-
phone: "123"
|
415
|
+
# Multiple validation failures
|
416
|
+
result = ValidationErrorTask.call(
|
417
|
+
email: "invalid-email",
|
418
|
+
age: "not-a-number",
|
419
|
+
phone: "123",
|
420
|
+
preferences: {
|
421
|
+
theme: "purple",
|
422
|
+
language: "invalid"
|
423
|
+
}
|
281
424
|
)
|
282
425
|
|
283
|
-
result.failed?
|
426
|
+
result.failed? # → true
|
284
427
|
result.metadata
|
285
|
-
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
289
|
-
#
|
290
|
-
#
|
291
|
-
#
|
428
|
+
# {
|
429
|
+
# reason: "email format is not valid. age could not coerce into an integer. phone format is not valid. theme purple is not included in the list. language invalid is not included in the list.",
|
430
|
+
# messages: {
|
431
|
+
# email: ["format is not valid"],
|
432
|
+
# age: ["could not coerce into an integer"],
|
433
|
+
# phone: ["format is not valid"],
|
434
|
+
# theme: ["purple is not included in the list"],
|
435
|
+
# language: ["invalid is not included in the list"]
|
292
436
|
# }
|
437
|
+
# }
|
293
438
|
```
|
294
439
|
|
440
|
+
> [!TIP]
|
441
|
+
> Parameter validation occurs before the `call` method executes, so you can rely on parameter presence and types within your task logic.
|
442
|
+
|
295
443
|
---
|
296
444
|
|
297
445
|
- **Prev:** [Configuration](../configuration.md)
|