Getting Started

Introduction

Paradocs = Extended Parametric gem + Documentation Generation

Ruby

Declaratively define data schemas in your Ruby objects, and use them to whitelist, validate or transform inputs to your programs.

Useful for building self-documeting APIs, search or form objects. Or possibly as an alternative to Rails' strong parameters (it has no dependencies on Rails and can be used stand-alone).

Installation

$ gem install paradocs

Or with Bundler in your Gemfile.

gem 'paradocs'

Try it out

Define a schema

schema = Paradocs::Schema.new do
  field(:title).type(:string).present
  field(:status).options(["draft", "published"]).default("draft")
  field(:tags).type(:array)
end

Populate and use. Missing keys return defaults, if provided.

form = schema.resolve(title: "A new blog post", tags: ["tech"])

form.output # => {title: "A new blog post", tags: ["tech"], status: "draft"}
form.errors # => {}

Undeclared keys are ignored.

form = schema.resolve(foobar: "BARFOO", title: "A new blog post", tags: ["tech"])

form.output # => {title: "A new blog post", tags: ["tech"], status: "draft"}

Validations are run and errors returned

form = schema.resolve({})
form.errors # => {"$.title" => ["is required"]}

If options are defined, it validates that value is in options

form = schema.resolve({title: "A new blog post", status: "foobar"})
form.errors # => {"$.status" => ["expected one of draft, published but got foobar"]}

Nested schemas

A schema can have nested schemas, for example for defining complex forms.

person_schema = Paradocs::Schema.new do
  field(:name).type(:string).required
  field(:age).type(:integer)
  field(:friends).type(:array).schema do
    field(:name).type(:string).required
    field(:email).policy(:email)
  end
end

It works as expected

results = person_schema.resolve(
  name: "Joe",
  age: "38",
  friends: [
    {name: "Jane", email: "jane@email.com"}
  ]
)

results.output # => {name: "Joe", age: 38, friends: [{name: "Jane", email: "jane@email.com"}]}

Validation errors use JSON path expressions to describe errors in nested structures

results = person_schema.resolve(
  name: "Joe",
  age: "38",
  friends: [
    {email: "jane@email.com"}
  ]
)

results.errors # => {"$.friends[0].name" => "is required"}