
Security News
Follow-up and Clarification on Recent Malicious Ruby Gems Campaign
A clarification on our recent research investigating 60 malicious Ruby gems.
DTO-Schema is a small Ruby library to validate simple data.
gem install dto_schema
DTO-Schema validates a "simple data". A notion of "simple data" could be defined as follows:
nil
is a simple dataString
is a simple dataNumeric
is a simple dataArray
of simple data is a simple data itselfHash
with symbolic keys and simple-data values is a simple data itselfDefine a schema:
require 'dto_schema'
schema = DTOSchema::define do
object :tag do
required :name, String, check: [:not_empty]
required :value, String, check: [:not_empty]
end
object :post do
required :title, String, check: [:not_empty]
optional :tags, list[:tag]
end
check :not_empty do |value|
next "Cannot be empty" if value.empty?
end
end
And then use it to validate data:
require 'json'
data = JSON.parse('{"tags":[42, {"name":"", "value":"foo"}]}', symbolize_names: true)
p schema.post.validate data
And result will be:
{:title=>["Cannot be null"], :tags=>{0=>["Must be object"], 1=>{:name=>["Cannot be empty"]}}}
DTO-Schema is defined with DTOSchema::define
method
require 'dto_schema'
schema = DTOSchema::define do
# schema definition goes here ...
end
Use the object <name> do <definition> end
method to define a new DTO type:
require 'dto_schema'
schema = DTOSchema::define do
object :post do
required :title, String
optional :body, String
end
end
Each DTO definition provides required
and optional
method to declare DTO attributes.
The schema above defines post
DTO with optional attribute body
and required attribute title
.
For each defined DTO schema provides a number of dynamically-generated methods to access it.
For example if we define a post
DTO as shown above, the schema will have the
following methods:
post
- to get the post-validatorpost? (data)
- to check if the data has a valid structure
(equivalent of schema.post.valid_structure? data
, more on this later)valid_post? (data)
- to check if data is a valid post
DTO (a short-hand of schema.post.valid? data
)validate_post (data)
- get the data validation errors (a short-hand of schema.post.validate data
)For example:
data = {
body: 42
}
p schema.validate_post data
{:body=>["Must be a String"], :title=>["Cannot be null"]}
To apply a custom checks to a DTO attributes, required
and optional
methods accept
an optional block which is called during validation with an attribute value as an argument.
A block must return either an Array of error-messages, a single error message or nil
.
Example:
schema = DTOSchema::define do
object :post do
required :title, String do |value|
next "Cannot be empty" if value.empty?
end
optional :body, String do |value|
next "Cannot be empty" if value.empty?
end
end
end
data = {
title: true,
body: ""
}
p schema.validate_post data
{:title=>["Must be a String"], :body=>["Cannot be empty"]}
You can define and reuse checks using a check
method.
Each attribute may have any number of checks.
schema = DTOSchema::define do
object :post do
required :title, String, check: :not_empty
optional :body, String, check: [:not_empty]
end
check :not_empty do |value|
next "Cannot be empty" if value.empty?
end
end
This is an equivalent of the previous example.
Sometimes it is useful to define a parametrized checks. It could be done like this:
schema = DTOSchema::define do
object :post do
required :title, String, check: check.length(min: 3)
optional :body, String, check: check.length(max: 2)
end
check :length do |value, min: 0, max: nil|
next "Must contain at least #{min} chars" if value.size < min
next "Must contain at max #{max} chars" if !max.nil? && value.size > max
end
end
data = {
title: "hi",
body: "foo"
}
p schema.validate_post data
{:title=>["Must contain at least 3 chars"], :body=>["Must contain at max 2 chars"]}
You may define any number of DTOs and embed one into another. To do that you simply use dto name as an attribute type.
schema = DTOSchema::define do
object :book_details do
required :pages, Numeric
required :author, String
required :language, String
end
object :book do
required :title, String
required :text, String
required :details, :book_details
end
end
data = {
title: "Moby-Dick",
text: "Call me Ishmael...",
details: {
author: "Herman Melville",
pages: 768,
}
}
p schema.validate_book data
{:details=>{:language=>["Cannot be null"]}}
DTO-Schema provides a list
method to define list-attributes:
schema = DTOSchema::define do
object :book do
required :title, String
required :pages, list[String]
end
end
data = {
title: "Moby-Dick",
pages: ["Call me Ishmael...", 42]
}
p schema.validate_book data
{:pages=>{1=>["Must be a String"]}}
You may reference any DTO as a list item type:
schema = DTOSchema::define do
object :tree do
required :value, Numeric
optional :child, list[:tree]
end
end
data = {
value: 42,
child: [
{
value: 12
},
{
value: "wrong!"
}
]
}
p schema.validate_tree data
{:child=>{1=>{:value=>["Must be a Numeric"]}}}
List item type may be any valid type including list itself: list[list[Numeric]]
.
DTO-Schema allows to declare list as independent DTO type
schema = DTOSchema::define do
object :polygon do
required :name, String
optional :vertices, list[:point]
end
list :point, Float do |items|
next "Must contain exactly 2 items" unless items.size == 2
end
end
data = {
name: "My Polygon",
vertices: [
[1.0, 2.0],
[5.0]
],
}
p schema.validate_polygon data
p schema.point? [1.0, 2.0]
{:vertices=>{1=>["Must contain exactly 2 items"]}}
true
Sometimes it is useful to check some invariants across DTO attributes.
To declare such validation DTO-Schema provides an invariant (fields, &block)
method.
schema = DTOSchema::define do
object :new_account do
required :password, String
required :confirm_password, String
invariant :confirm_password do |data|
next "Passwords must be equal" if data[:password] != data[:confirm_password]
end
end
end
data = {
password: "foo",
confirm_password: "bar",
}
p schema.validate_new_account data
{:confirm_password=>["Passwords must be equal"]}
Ruby doesn't have a single class for boolean values (instead it has TrueClass
and FalseClass
).
DTO-Schema provides a bool
method to expect boolean attribute type.
Sometimes we want to verify that some attribute is presented whatever value it has. For this purpose
DTO-Schema provides an any
method that could be used as attribute type.
schema = DTOSchema::define do
object :envelope do
required :custom_data, any
required :flags, list[bool]
end
end
data = {
custom_data: {
anything: "whatever"
},
flags: [true, false, 42]
}
p schema.validate_envelope data
{:flags=>{2=>["Must be boolean"]}}
FAQs
Unknown package
We found that dto_schema demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A clarification on our recent research investigating 60 malicious Ruby gems.
Security News
ESLint now supports parallel linting with a new --concurrency flag, delivering major speed gains and closing a 10-year-old feature request.
Research
/Security News
A malicious Go module posing as an SSH brute forcer exfiltrates stolen credentials to a Telegram bot controlled by a Russian-speaking threat actor.