Skip to content

Better Schema API

Compare
Choose a tag to compare
@eliasjpr eliasjpr released this 26 Dec 16:12
· 23 commits to master since this release
1cffd0c

Changes

  • No longer uses custom param keyword to define schemas, simply create your objects as plain old crystal objects POCOs
  • Use either nested objects or objects defined elsewhere in the codebase.
  • No longer uses validation do ... end macro to define validations, simply use validate :field, ..{predicates}, message: {error message}
  • POCOs that include the Schema::Validation module will have a nested validator class. For example, a class User will have a User::Validator class this makes the validator reusable.
  • POCOs that include the Schema::Validation module will have:
    • errors runs the Validator.validate method with an instance of the class returns an Array(Schema::Error)
    • valid? checks if the errors are empty if empty then is valid
    • validate! checks if the errors are empty if empty then is valid or raises Schema::ValidationError

Examples

class Address
    include Schema::Definition

    getter street : String
    getter zip : String
    getter city : String
    getter location : Location
  end

  class Location
    include Schema::Definition

    getter longitude : Float64
    getter latitude : Float64
    getter useful : Bool
  end

struct Example
  include Schema::Definition
  include Schema::Validation

  getter email : String
  getter name : String
  getter age : Int32
  getter alive : Bool
  getter childrens : Array(String)
  getter childrens_ages : Array(Int32)
  getter address : Address
  
  # Custom Validators
  use EmailValidator, UniqueRecordValidator

  validate :email, match: /\w+@\w+\.\w{2,3}/, message: "Email must be valid!"
  validate :name, size: (1..20)
  validate :age, gte: 18, lte: 25, message: "Age must be 18 and 25 years old"
  validate :alive, eq: true
  validate :last_name, presence: true, message: "Last name is invalid"
  
  # Custom Predicates
  predicates do
    def some?(value : String, some) : Bool
      (!value.nil? && value != "") && !some.nil?
    end

    def if?(value : Array(Int32), bool : Bool) : Bool
      !bool
    end
  end
end

Example Custom Validators

class EmailValidator < Schema::Validator
  include Schema::Validators
  getter :record, :field, :message

  def initialize(@record : UserModel)
    @field = :email
    @message = "Email must be valid!"
  end

  def valid? : Array(Schema::Error)
    [] of Schema::Error
  end
end

class UniqueRecordValidator < Schema::Validator
  getter :record, :field, :message

  def initialize(@record : UserModel)
    @field = :email
    @message = "Record must be unique!"
  end

  def valid? : Array(Schema::Error)
    [] of Schema::Error
  end
end