Ruby Object Coercion and Validation
This is a straight forward way to validate any Ruby object: just give an object and the schema.
The motivation was to create an integration for RestMyCase to have validations before any business logic execution and to build a easy way coerce and validate params on Sinatra.
The schema builder is based on Joi.
object = {
first_name: 'Joaquim',
birth_date: '1989-0',
address: {
line_one: 'Lisboa',
post_code: '1100',
country_code: 'PT'
}
}
schema = Compel.hash.keys({
first_name: Compel.string.required,
last_name: Compel.string.required,
birth_date: Compel.datetime,
address: Compel.hash.keys({
line_one: Compel.string.required,
line_two: Compel.string.default('-'),
post_code: Compel.string.format(/^\d{4}-\d{3}$/).required,
country_code: Compel.string.in(['PT', 'GB']).default('PT')
})
})
Compel.run(object, schema) # or schema.validate(object)
Will return a Compel::Result
object:
=> <Compel::Result
@errors={
"last_name" => ["is required"],
"birth_date" => ["'1989-0' is not a parsable datetime with format: %FT%T"],
"address" => {
"post_code" => ["must match format ^\\d{4}-\\d{3}$"]
}
},
@valid=false,
@value={
"first_name" => "Joaquim",
"birth_date" => "1989-0",
"address" => {
"line_one" => "Lisboa",
"post_code" => "1100",
"country_code" => "PT",
"line_two" => "-"
},
"errors" => {
"last_name" => ["is required"],
"birth_date" => ["'1989-0' is not a parsable datetime with format: %FT%T"],
"address" => {
"post_code" => ["must match format ^\\d{4}-\\d{3}$"]
}
}
}>
There are 4 ways to run validations:
Method | Behaviour |
---|---|
#run |
Validates and returns a Compel::Result (see below) |
#run! |
Validates and raises Compel::InvalidObjectError exception with the coerced params and errors. |
#run? |
Validates and returns true or false. |
schema#validate |
Check below |
==========================
Any
referes to any type that is available to coerce with Compel.
Methods length
, min_length
and max_length
turn the object to validate into a string
to compare the length.
Methods:
is(``value``)
required
default(``value``)
length(``integer``)
min_length(``integer``)
max_length(``integer``)
if
if(->(value){ value == 1 })
if{|value| value == 1 }
if{:custom_validation} # Check the specs for now, I'm rewriting the docs ;)
==========================
Methods:
#items(``schema``)
Examples:
. [1, 2, 3]
. [{ a: 1, b: 2}
. { a: 3, b: 4 }]
==========================
Methods:
keys(``schema_hash``)
Examples:
. { a: 1, b: 2, c: 3 }
==========================
Methods:
format(``ruby_date_format``)
iso8601
, set format to:%Y-%m-%d
==========================
Methods:
format(``ruby_date_format``)
iso8601
, set format to:%FT%T
==========================
Examples:
. "{\"a\":1,\"b\":2,\"c\":3}"
==========================
Examples:
. 1/0
. true/false
. 't'/'f'
. 'yes'/'no'
. 'y'/'n'
==========================
Methods:
in(``array``)
min(``value``)
max(``value``)
format(``regexp``)
email
url
==========================
Methods:
in(``array``)
min(``value``)
max(``value``)
==========================
Methods:
in(``array``)
min(``value``)
max(``value``)
==========================
For straight forward validations, you can call #validate
on schema and it will return a Compel::Result
object.
result = Compel.string
.format(/^\d{4}-\d{3}$/)
.required
.validate('1234')
puts result.errors
# => ["must match format ^\\d{4}-\\d{3}$"]
Simple object that encapsulates a validation result.
Method | Behaviour |
---|---|
#value |
the coerced value or the input value is invalid |
#errors |
array of errors is any. |
#valid? |
true or false |
#raise? |
raises a Compel::InvalidObjectError if invalid, otherwise returns #value |
Custom error message
Examples:
schema = Compel.string.required(message: 'this is really required')
result = schema.validate(nil)
p result.errors
=> ["this is really required"]
schema = Compel.string.is('Hello', message: 'give me an Hello!')
result = schema.validate(nil)
p result.errors
=> ["give me an Hello!"]
==========================
If you want to use with Sinatra
, here's an example:
class App < Sinatra::Base
set :show_exceptions, false
set :raise_errors, true
before do
content_type :json
end
helpers do
def compel(schema)
params.merge! Compel.run!(params, Compel.hash.keys(schema))
end
end
error Compel::InvalidObjectError do |exception|
status 400
{ errors: exception.object[:errors] }.to_json
end
configure :development do
set :show_exceptions, false
set :raise_errors, true
end
post '/api/posts' do
compel({
post: Compel.hash.keys({
title: Compel.string.required,
body: Compel.string,
published: Compel.boolean.default(false)
}).required
})
params.to_json
end
end
###Installation
Add this line to your application's Gemfile:
gem 'compel', '~> 0.5.0'
And then execute:
$ bundle
If you have any questions, write an issue or get in touch @joaquimadraz