Skip to content
Elixir data validation library
Branch: master
Clone or download
bobfp Merge pull request #11 from chanon/master
Fixed error raised when expecting list but data is not a list
Latest commit c07ff12 May 1, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
config name changed Dec 12, 2017
lib fixed error raised when expecting list but data is not a list May 1, 2019
test add map custom validator test case Mar 14, 2018
.gitignore initial POC Dec 9, 2017
.travis.yml Create .travis.yml Feb 19, 2018
LICENSE Create LICENSE Dec 14, 2017 Update Feb 19, 2018
mix.exs update version number Jan 5, 2018
mix.lock added mix info and started docs Dec 14, 2017

Skooma Build Status

Simple data validation library for elixir.

Skooma was developed to be used to describe and validate the incoming and outgoing data structures from a REST API, but it can easily be used throughout a code base. No one likes writing data schemas, so the main focus during development was to develop an API that allowed for quick and simple schema creation.

Table of Contents


the package can be installed by adding skooma to your list of dependencies in mix.exs:

def deps do
    {:skooma, "~> 0.2.0"}


Skooma exposes the function valid?/2

data = %{
  :race => "Khajiit",
  :name => "Bob",
  :level => 6,
  "potions" => ["Skooma", "Fortify Health", "Fortify Magicka"]
schema = %{
  :race => :string,
  :name => :string,
  :level => :int,
  :gender => [:atom, :not_required]
  "potions" => [:list, :string],
Skooma.valid?(data, schema)
# :ok


Skooma supports all of the elixir data types:


data = false
schema = :bool
Skooma.valid?(data, schema) #:ok


data = "test"
schema = :string
Skooma.valid?(data, schema) #:ok


data = 7
schema = :int
Skooma.valid?(data, schema) #:ok


data = 3.14
schema = :float
Skooma.valid?(data, schema) #:ok


data = 1.41
schema = :number
Skooma.valid?(data, schema) #:ok


data = :thing
schema = :atom
Skooma.valid?(data, schema) #:ok


data = %{
  :race => "Khajiit",
  "level" => 6,
schema = %{
  :race => :string,
  "level" => :int,
Skooma.valid?(data, schema) # :ok


data = [1, 2, 3]
schema = [:list, :int]
Skooma.valid?(data, schema) # :ok


data = {456.89, 365.65}
schema = {:float, :float}
Skooma.valid?(data, schema) # :ok

Keyword List

data = [key1: "value1", key2: 2, key3: :atom3]
schema = [key1: :string, key2: :int, key3: :atom]
Skooma.valid?(data, schema) # :ok

Complex Schemas

Not Required

Sometimes, you want a field to be optional. In this case, use the :not_required atom.

data = %{"key2" => 3}
schema = %{:key1 => [:string, :not_required], "key2" => :int}
Skooma.valid?(data, schema) # :ok

A nil value will also pass if :not_required is invoked

data = %{:key1 => nil, "key2" => 3}
schema = %{:key1 => [:string, :not_required], "key2" => :int}
Skooma.valid?(data, schema) # :ok

Complex Maps

Skooma schemas can be nested and combined to match any data strucutre.

my_hero = %{
  race: "Khajiit",
  stats: %{
    hp: 100,
    magicka: 60,
    xp: 5600
schema = %{
  race: :string,
  stats: %{
    hp: :int,
    magicka: :int,
    xp: :int
Skooma.valid?(data, schema) # :ok

For flexibilty and incase of recursive data structures, functions that return maps can also be used. In this case, the :map type must be explicitly used

my_hero = %{
  name: "Alkosh"
  race: "Khajiit",
  friends: [ 
    %{name: "Asurah", race: "Khajiit"}, 
    %{name: "Carlos", race: "Dwarf"}

def hero_schema() do
    name: :string,
    race: :string,
    friends: [:list, :map, :not_required, &hero_schema/0]
Skooma.valid?(my_hero, hero_schema) # :ok

Union Types

Skooma also lets you supply a list of schemas to allow for flexible data structures

data1 = %{key1: "value1"}
data2 = 8

schema = [:union, [%{key1: :string}, :int]]

Skooma.valid?(data1, schema) # :ok
Skooma.valid?(data2, schema) # :ok

Error Handling

If a the data and schema passed to valid?/2 match, an :ok will be returned.

If a match isn't made, valid?/2 returns something of the form {:error, ["Error Mesasge 1", "Error Message 2"...])

A few examples are:

data = 7
schema = [:string]
Skooma.valid?(data, schema) # {:error, ["Expected STRING, got INTEGER 7"]}
data = %{
  :key1 => "value1",
  "key2" => %{color: "blue"},
  "things" => ["thing1", 5],
  "stuff" => %{key3: %{key4: 9}}
schema = %{
  :key1 => [:string],
  "key2" => [:map, %{color: [:string]}],
  "things" => [:list, :string],
  "stuff" => %{key3: %{key4: [:string]}}
Skooma.valid?(data, schema) # => 
# {:error, [
#  "Expected STRING, got INTEGER 9, at stuff -> key3 -> key4",
#  "Expected STRING, got INTEGER 5, at things -> index 1"
# ]}


Skooma comes with a few additional functions that can be used to perform more complex validation.

data = "abc"
schema = [:string, Validators.min_length(4)]
Skooma.valid?{data, schema) # {:error, ["String must be longer than 4 characters"]}

Multiple validators can also be used at the same time:

data = "duck"
schema = [:string, Validators.regex(~r/foo/), Validators.max_length(5)]
Skooma.valid?{data, schema) # {:error, ["String does not match the regex pattern: ~r/foo/"]}

Custom Validators

There is nothing special about the validator functions that Skooma comes with. Making your own is super easy.

There are two types of custom validators. The most barebones is any function that accepts one argument and returns a boolean:

data = 8
schema = [:int, &(&1 == 0)]
Skooma.valid?{data, schema) # {:error, ["Value does not match custom validator"]}

However, if you need more flexibility or a custom error message, instead of returning a boolean, your function should return either :ok or {:error, "Your Custom Error Message"}. Take the built it max_length validator as an example:

def max_length(max) do
    fn (data) ->
      bool = String.length(data) <= max
      if bool do
        {:error, "String must be shorter than #{max} characters"}

data = "abcdefghijk"
schema = [:string, Validators.max_length(7)]
Skooma.valid?{data, schema) # {:error, ["String must be shorter than 7 characters"]}


All contributions are welcome. If there is a validator you would like to see added to the library, please create an issue!


MIT © bcoop713

You can’t perform that action at this time.