View Source Draft
Draft is a library for building structs with runtime type validation. Creating and validating structs has never been easier. Inspired by Ecto.Schema
usage
Usage
setup
Setup
To use Draft in your project, add this to your Mix dependencies:
{:draft, "~> 1.0.0"},
general-usage
General usage
To define a Simple blueprint struct
defmodule StructType do
use Draft.Schema
# Define your struct.
schema do
#Define a field with type string
field :name, :string
field :id, :uuid
#Define a field with default value
field :age, :number, default: 10
field :amount, :float
end
end
Nested blueprints
defmodule Nested do
use Draft.Schema
schema do
field :value, :number
end
end
defmodule Typed do
use Draft.Schema
schema do
# Nested field
field :nested, Nested, default: nil
field :name, :string, default: "my name"
end
end
inheritance
Inheritance
Draft structs can inherit fields from other schema, their types and validation rules, using the :extends
option
:extends
Draft module or list of blueprint modules for inheriting from muliple bases
Inherit from single base
defmodule Super do
use Draft.Schema
schema do
field :super, :number
end
end
defmodule Base do
schema extends: Super do
field :base, :number
end
end
defmodule Child do
use Draft.Schema
schema extends: Base do
field :child, :number
end
end
%Child{super: 1, base: 2, child: 3}
Inherit from multiple base modules
when inheriting from multiple bases, the next module in the list always overwrites any previously defined fields
schema extends: [Base, Super]
the module Super
will overwrite any fields already defined in Base
defmodule Super do
use Draft.Schema
schema do
field :super, :number
end
end
defmodule Base do
use Draft.Schema
schema do
field :base, :number
end
end
defmodule Child do
use Draft.Schema
schema extends: [Base, Super] do
field :child, :number
end
end
%Child{super: 1, base: 2, child: 3}
Sometime users may wish to overwrite certain fields with custom rules or type,
this can be done with the overwrite
field option
overwrite field base definition
defmodule Super do
use Draft.Schema
schema do
field :super, :number
end
end
defmodule Base do
use Draft.Schema
schema do
field :base, :number
end
end
defmodule Child do
use Draft.Schema
schema extends: [Base, Super] do
field :base, :string, overwrite: true
end
end
%Child{super: 1, base: "2", child: 3}
methods
Methods
Draft defines a constructor new
method to create
struct from map or list. Note: the new method will throw if
validation of field type fails
data = StructType.new(%{...})
Draft defines a constructor cast
method to struct but unlike
the new
method is returns the usual {:ok, value}
or {:error, reason}
{:ok, data} = StructType.cast(%{...})
{:error, reason} = StructType.cast(123)
Draft defines a constructor from_struct
just like new
but made to look like
the familiar Map.from_struct
is uses the new
method and will throw if
validation fails
data = StructType.from_struct(%StructType{...})
Draft defines a dump
method to dump the data to simple Map that can be easily
serializable
{:ok, data} = StructType.dump(%StructType{...})
advanced-usage
Advanced usage
required-fields
Required fields
Defining required fields is simple required fields cannot be nil
There are multiple way of going about this
Make all fields required
defmodule StructType do
use Draft.Schema
# This will make all fields required.
schema [required: true] do
field :id, :uuid
field :name, :string
field :age, :number
field :amount, :float
end
end
Exclude some fields from being required
By making the default value of a field nil
that field becomes nullable
defmodule StructType do
use Draft.Schema
# This will make all fields required.
schema [required: true] do
field :id, :uuid
field :name, :string
field :age, :number
# This field will can by nill
field :amount, :float, default: nil
end
end
Make select fields required
By making the default value of a field nil
that field becomes nullable
defmodule StructType do
use Draft.Schema
# This will make all fields nill by default except id.
schema do
# Ensure id is required
field :id, :uuid, required: true
field :name, :string
field :age, :number
field :amount, :float
end
end
draft-types
Draft types
- any
- map
- enum
- atom
- uuid
- tuple
- float
- array
- struct
- number
- string
- boolean
- integer
- datetime
map
defmodule Typed do
use Draft.Schema
@mapping [
name: [:string, length: [min: 5, max: 10]],
value: [:number, required: false]
]
schema do
# Define map with fields
field :map_type, :map, fields: @mapping
end
end
nested types
defmodule Nested do
use Draft.Schema
schema do
field :value, :number
end
end
defmodule Typed do
use Draft.Schema
schema do
field :nested_array, :array, type: Nested, default: []
end
end
draft-validators
Draft validators
- inclusion
- exclusion
- required
- length
- format
- number
- fields
- struct
- uuid
- type
- by
- tld
- pattern
required
validate required, field must have a value except nil
defmodule Typed do
use Draft.Schema
schema do
field :name, :string, required: true
end
end
length
validate length
defmodule Typed do
use Draft.Schema
schema do
field :name, :string, length: [min: 2, max: 20]
end
end
pattern
validate pattern
defmodule Typed do
use Draft.Schema
schema do
field :email, :string, pattern: :email
end
end
customization
Customization
draft-type
Draft.Type
Draft types all implement the Draft.Type.Behaviour
defining a new type
must implement this behaviour
defmodule CustomInteger do
@behaviour Draft.Type.Behaviour
def cast(value, options) when is_integer(value) do
{:ok, value}
end
def cast(value, options) do
{:error, ["value must be integer"]}
end
def dump(data, options) do
{:ok, data}
end
end
draft-validator
Draft.Validator
Draft types all implement the Draft.Type.Behaviour
defining a new type
must implement this behaviour
defmodule CustomValidator do
@behaviour Draft.Validator.Behaviour
# validate a value given a context and options
# defined in field definition
def validate(value, context, options) do
{:ok, value}
end
# vaidate return error tuple when value
# value fails validation
def validate(value, context, options) do
{:error, ["reason"]}
end
end
Draft types and validators can be defined or overwritten using config
config :types, Draft,
map: CustomMapImpl,
custom_integer: CustomInteger,
typename1: CustomType,
typename2: CustomTypeImpl2
config :validators, Draft,
validatorname: CustomValidator,
seondvalidator: CustomSecondValidatorImpl
use custom types and validators with Draft
defmodule CustomType do
use Draft.Schema
# Define your struct.
schema do
#Define a field with type string
field :name, :string, validatorname: [...opts]
#Define a field with custom integer type
field :age, :custom_integer, default: 10
end
end
thats-all-there-is-to-blueprint
Thats all there is to blueprint
todo
Todo
- [ ] Field documention
- [ ] Validation documention