Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to enforce a schema for a JSON field within a Postgresql record in Rails?

I am dabbling with json fields in Postgres. So I am using activerecord for most validation. But, I'd like to add a json field and be able to validate that. Is there a clean way to do this? I guess I could always create my own validation function but it seems like there would be a better way that may take advantage of json schemas? Has anyone had success with this?

like image 644
kidbrax Avatar asked Oct 20 '25 15:10

kidbrax


2 Answers

You can use the json-schema gem:

schema = {
  "type" => "object",
  "required" => ["a"],
  "properties" => {
    "a" => {"type" => "integer"}
  }
}
JSON::Validator.validate(schema, { "a" => 5 }) 
# => true
JSON::Validator.validate(schema, { "a" => "five" })
# => false 

Note that this a validator in the broader sense of the term - not a validator that can be directly used with ActiveRecord.

Writing a custom ActiveModel validator is pretty easy though:

require "json-schema"
class SchemaValidator < ActiveModel::EachValidator

  def validate_each(record, attribute, value)
    # Looks for a JSON schema as a class constant
    c = "#{attribute.upcase}_SCHEMA"
    begin 
      schema = record.class.const_get(c)
    rescue NameError => e
      # re-raise exception with a more descriptive message
      raise( 
        $!, 
        "Expected #{record.class.name}::#{c} to declare a JSON Schema for #{attribute}", 
        $!.backtrace
      )
    end
    unless JSON::Validator.validate(schema, value)
      record.errors.add(attribute, 'does not comply to JSON Schema')
    end
  end
end

We can then use it like so:

class Thing < ActiveRecord::Base
  FOO_SCHEMA = {
    "type" => "object",
    "required" => ["a"],
    "properties" => {
      "a" => {"type" => "integer"}
    }
  }

  validates :foo, schema: true
end
like image 172
max Avatar answered Oct 22 '25 03:10

max


You could also check json at database level. As far as I know there are two libraries that validate JSONs in PostgreSQL:

  • Postgres JSON Schema written in SQL
  • is_jsonb_valid written in C. (disclaimer I've written the library)

Once you have installed one of them you could do:

ALTER TABLE my_table ADD CONSTRAINT data_is_valid CHECK (validate_json_schema('{/*your schema here */}', my_json));

if you are using Postgres JSON schema, and:

ALTER TABLE my_table ADD CONSTRAINT data_is_valid CHECK (is_jsonb_valid('{/*your schema here */}', my_json));

if you are using is_jsonb_valid.

like image 28
Gabriel Furstenheim Avatar answered Oct 22 '25 05:10

Gabriel Furstenheim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!