0.0
Low commit activity in last 3 years
No release in over a year
Easy way to create models from payloads
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

schema

Fast and easy way to transform data into models for validation and type safety.

Build Status Maintainability Test Coverage

Attributes of a model have a name and type. Any value passed in goes through a parser method. If the value can not be parsed successfully the error is added to parsing_errors.

Associations are nested schema models. Each association can have its own set of attributes.

Dynamic associations are useful when creating custom logic around schema validation.

Example that show cases multiple features

spec/examples/company_schema.rb
# frozen_string_literal: true

# Example that show cases multiple features
class CompanySchema
  # includes model, associations, parsers and active model validations
  include Schema::All

  # add common attributes
  # attributes support additional names through the alias(es) option
  attribute :name, :string, alias: 'CompanyName'
  attribute :industry_type, :string, aliases: %w[IndustryType industry]

  # will take a string split on the separator and use the parse_<data_type> method on every element
  # basically take a list of comma separated numbers and create an array of integers
  # code snippet: str.split(',').map { |v| parse_integer(field_name, parsing_errors, v) }
  attribute :number_list, :array, separator: ',', data_type: :integer

  # creates a nested dynamic schema based on the industry_type which is part of the main company data
  industry_schema = has_one(:industry, external_type_field: :industry_type) do
    attribute :name, :string

    validates :name, presence: true

    add_type('tech') do
      attribute :custom_description, :string
    end

    add_type('qsr') do
      attribute :number_of_locations, :integer

      # custom validation
      validates :number_of_locations, presence: true
    end
  end

  # create multiple dynamic location schemas based on the type field in the location data
  has_many(:locations, type_field: :type) do
    attribute :type, :string
    attribute :address, :string
    attribute :city, :string
    attribute :state, :string
    attribute :zip, :string

    add_type('headquarters') do
      attribute :main_floor, :integer

      validates :city, presence: true
      validates :main_floor, presence: true
    end

    add_type('store_front') do
      attribute :main_entrance, :string

      validates :address, presence: true
      validates :main_entrance, presence: true
    end
  end

  # create multiple dynamic employee schemas based on the type field in the employee data
  has_many(:employees, type_field: :type) do
    attribute :type, :integer
    attribute :name, :string
    attribute :start_date, :date
    add_type(1) do # worker
      attribute :manager_name, :string
    end
    add_type(2) do # manager
      attribute :rank, :float
    end
    # if no or an invalid type is specified, create a default employee schema object
    # useful for communicating errors in an API
    default_type

    # dynamic_type_names returns all the types used, except for :default
    validates :type, inclusion: { in: dynamic_type_names }
  end

  has_many(:admins, from: :hash, hash_key_field: :username) do
    attribute :username, :string
    attribute :email, :string
    attribute :name, :string

    validates :username, presence: true
    validates :email, presence: true
  end

  validates :name, presence: true
  validates :industry_type, inclusion: { in: industry_schema.dynamic_type_names }

  # use the schema validator
  validates :industry, presence: true, schema: true
  validates :locations, presence: true, schema: true
  validates :employees, presence: true, schema: true
  validates :admins, presence: true, schema: true
end
spec/examples/company_schema.json
{
  "CompanyName": "Good Burger",
  "IndustryType": "qsr",
  "industry": {
    "name": "Food & Beverage",
    "number_of_locations": 2
  },
  "locations": [
    {
      "type": "headquarters",
      "city": "Boston",
      "main_floor": 5
    },
    {
      "type": "store_front",
      "address": "1st Ave",
      "zip": "02211",
      "main_entrance": "side door"
    }
  ],
  "employees": [
    {
      "type": 2,
      "name": "Queen Bee",
      "start_date": "2016-01-09",
      "rank": "0.9"
    },
    {
      "type": 1,
      "name": "Worker Bee",
      "start_date": "2018-05-10",
      "manager_name": "Queen Bee"
    }
  ],
  "admins": {
    "captain": {
      "email": "captain@example.com",
      "name": "Captain Kurk"
    },
    "joe": {
      "email": "joe.smith@example.com",
      "name": "Joe Smith"
    }
  }
}