crossbar

Types

The CrossBarError type is used to represent errors that occur during validation.

pub type CrossBarError {
  FailedRule(name: String, rule: String, error: String)
}

Constructors

  • FailedRule(name: String, rule: String, error: String)
pub type JsonMode {
  Array
  KeyValue
}

Constructors

  • Array

    Return errors as an array of error strings

    ["is required", "must be at least 5 characters"]
    
  • KeyValue

    Return errors as an object with the rule name as the key and the error string as the value

    { "required": "is required", "min_length": "must be at least 5 characters" }
    
pub type ValidationResult(a) =
  Result(Field(a), List(CrossBarError))

Functions

pub fn bool(name name: String, value value: Bool) -> Field(Bool)

Creates a new Bool field with the given name and value

pub fn eq(
  field field: Field(a),
  name name: String,
  value value: a,
) -> Field(a)

The eq rule makes sure that the field is equal to the given value, strings are NOT compared securely, so this is NOT safe to use for passwords, all types are compared directly.

pub fn extract_errors(
  result: Result(Field(a), List(CrossBarError)),
) -> List(#(String, String))

Useful for extracting the errors as a list of tuples (#(rule_name, error_as_string)), this is useful for returning errors as JSON.

pub fn float(
  name name: String,
  value value: Float,
) -> Field(Float)

Creates a new Float field with the given name and value

pub fn has_errors(json_errors: List(#(String, Json))) -> Bool

Useful for checking if the result of to_serializable collected into a list has any errors, this is useful for checking if any of the fields failed validation.

Example

let first_name =
  string("first_name", "John")
  |> required
  |> min_length(3)
  |> to_serializable(KeyValue)

let last_name =
  string("last_name", "Smith")
  |> required
  |> min_length(1)
  |> max_length(10)
  |> to_serializable(KeyValue)

let errors = [first_name, last_name]

case has_errors(errors) {
  True -> io.println("There are errors")
  False -> io.println("There are no errors")
}
pub fn int(name name: String, value value: Int) -> Field(Int)

Creates a new Int field with the given name and value

pub fn max_length(
  field field: Field(String),
  length length: Int,
) -> Field(String)

The max_length rule makes sure that the field is at most the given length, this is the expected behaviour in the following cases:

Int: the length of the string representation of the number, this isn’t very useful to you, but it’s here for completeness sake. You probably want to use max_value instead.

Float: the length of the string representation of the number, this also isn’t very useful to you, but it’s here for completeness sake. You probably want to use max_value instead.

String: the length of the string is evaluated directly

Bool: this also isn’t very useful to you, but it’s here for completeness sake.

NOTE: This function has been momentarily restricted to String fields, because it’s not very useful for other types, open an issue if you ever find a use for it.

pub fn max_value(
  field field: Field(Float),
  size size: Float,
) -> Field(Float)

The max_value rule makes sure that the field is at most the given (byte) size.

Strings are counted in bytes (as bit arrays), Ints and Floats are evaluated directly, Bools are treated as their binary equivalent (0 or 1).

NOTE: This function has been momentarily restricted to Float fields, because it’s not very useful for other types, open an issue if you ever find a use for it. There is also a to_float function to transform int fields to float fields (meant to be used before you add any rules)

pub fn min_length(
  field field: Field(String),
  length length: Int,
) -> Field(String)

The min_length rule makes sure that the field is at least the given length, this is the expected behaviour in the following cases:

Int: the length of the string representation of the number, this isn’t very useful to you, but it’s here for completeness sake. You probably want to use min_value instead.

Float: the length of the string representation of the number, this isn’t very useful to you, but it’s here for completeness sake. You probably want to use min_value instead.

String: the length of the string is evaluated directly

Bool: this also isn’t very useful to you, but it’s here for completeness sake.

NOTE: This function has been momentarily restricted to String fields, because it’s not very useful for other types, open an issue if you ever find a use for it.

pub fn min_value(
  field field: Field(Float),
  size size: Float,
) -> Field(Float)

The min_value rule makes sure that the field is at least the given (byte where it applies) size.

Strings are counted in bytes (as bit arrays), Ints and Floats are evaluated directly, Bools are treated as their binary equivalent (0 or 1).

NOTE: This function has been momentarily restricted to Float fields, because it’s not very useful for other types, open an issue if you ever find a use for it. There is also a to_float function to transform int fields to float fields (meant to be used before you add any rules)

pub fn not_eq(
  field field: Field(a),
  name name: String,
  value value: a,
) -> Field(a)

The not_eq rule makes sure that the field is not equal to the given value, strings are NOT compared securely, so this is NOT safe to use for passwords, other types are compared directly.

pub fn regex(
  field field: Field(a),
  rule_name name: String,
  regex regex: Regex,
  error_message error: String,
) -> Field(a)

The regex rule makes sure that the field matches the given regex, you are required to compile the regex yourself, if you want to use an uncompiled regex, use the uncompiled_regex rule instead.

Example

import gleam/regex

let options = Options(case_insensitive: False, multi_line: True)
let assert Ok(re) = compile("^[0-9]", with: options)

string("name", "1john")
|> regex("starts_with_number", re,  "must start with a number")
pub fn required(field field: Field(a)) -> Field(a)

The required rule makes sure that the field is not empty, this is the expected behaviour in the following cases:

Int: 0 is considered empty

Float: 0.0 is also considered empty

String: “” (or anything that trims down to that) is considered empty

Bool: this isn’t really a thing, but it’s here for completeness sake and it will always return true, because a bool is never empty (unless it is wrapped in an option)

pub fn rule_to_error_string(rule: Rule(a)) -> String

Get the default error message for a rule - this is internally used for error states

pub fn rule_to_string(rule: Rule(a)) -> String

Returns the string representation of a rule - this is internally used for error states

pub fn serializables_to_string(
  serializables: List(#(String, Json)),
) -> String

Utility function to convert a list of serializable tuples into a JSON string.

pub fn string(
  name name: String,
  value value: String,
) -> Field(String)

Creates a new String field with the given name and value

pub fn to_float(field: Field(Int)) -> Field(Float)

Convenient function to convert an Int to a Float, you should use this BEFORE applying any rules.

Example

int("age", 6)
|> to_float
|> min_value(5.0)
pub fn to_serializable(
  result validation_result: Result(Field(a), List(CrossBarError)),
  field_name field_name: String,
  mode mode: JsonMode,
) -> #(String, Json)

Transform a field into a tuple that can be used to generate JSON, this is useful for returning errors as JSON. The field_name argument is optional, if you don’t provide it, the field name will be extracted from the validation result if it can be (which is usually the case).

Example

let first_name =
  string("first_name", "")
  |> required
  |> min_length(3)
  |> validate
  |> to_serializable("", KeyValue)

let last_name =
  string("last_name", "Smith")
  |> required
  |> min_length(1)
  |> max_length(3)
  |> validate
  |> to_serializable("renamed_last_field", KeyValue)

json.object([first_name, last_name])
|> json.to_string
|> io.println

The above example will produce the following JSON:

{
  "first_name": {
    "required": "is required",
    "min_length": "must be at least 3 characters"
  },
  "renamed_last_name": {
    "max_length": "must not be longer than 3 characters"
  }
}
pub fn to_serializable_list(
  results: List(#(String, List(CrossBarError))),
  mode: JsonMode,
) -> List(#(String, Json))

Validate a list of fields and transform them into a list of tuples that can be used to generate JSON, this is useful for returning errors as JSON.

Example

let first_name =
  string("first_name", "")
  |> required
  |> min_length(3)

let last_name =
  string("last_name", "Smith")
  |> required
  |> min_length(1)
  |> max_length(3)

to_serializable_list([first_name, last_name], KeyValue)
|> serializables_to_string
|> io.println

The above example will produce the following JSON:

{
  "first_name": {
    "required": "is required",
    "min_length": "must be at least 3 characters"
  },
  "last_name": {
    "max_length": "must not be longer than 3 characters"
  }
}
pub fn validate(
  field: Field(a),
) -> Result(Field(a), List(CrossBarError))

Run the validation on the given field, returns an Ok if the validation was successful, otherwise returns an Error with a list of errors.

Example

let field = int("age", 6)
|> to_float
|> min_value(5.0)
|> validate
pub fn validate_many(
  fields: List(Field(a)),
) -> List(#(String, List(CrossBarError)))

Validate a list of fields, returns a list of tuples with the field name and a list of errors - unfortunately, currently, only supports validating fields of the same type.

pub fn with_validator(
  field field: Field(a),
  rule_name name: String,
  validator func: fn(a) -> Bool,
  error error: String,
) -> Field(a)

The with_validator rule makes sure that the field passes the given validator function, the function should return a Bool and take the field value as its only argument.

Example

let validator = fn(x) { x > 5 }
let error = "must be greater than 5"

int("age", 6)
|> with_validator("greater_than_5", validator, error)
Search Document