Senko
Senko is a fast JSON Schema validator for Ruby. It compiles schemas into a reusable representation, uses generated Ruby code for simple boolean validation, and falls back to a full interpreter for detailed errors and advanced JSON Schema semantics.
Installation
Add this line to your application's Gemfile:
gem 'senko'
And then execute:
bundle install
Or install it yourself as:
gem install senko
Senko includes a native extension for validation hot paths. If the extension cannot be loaded, validation continues through the pure Ruby fallback.
Usage
Compile a schema once and reuse it:
require 'senko'
schema = Senko.compile(
'type' => 'object',
'required' => ['name'],
'properties' => {
'name' => { 'type' => 'string', 'minLength' => 1 }
},
'additionalProperties' => false
)
schema.valid?({ 'name' => 'senko' })
# => true
schema.valid?({ 'name' => '' })
# => false
Senko.compile accepts either a schema hash or schema keywords directly.
Senko.compile({ 'type' => 'string' })
Senko.compile('type' => 'string')
Validation
schema.valid?(data) # boolean-only validation
schema.validate(data) # returns Senko::Result
schema.validate!(data) # returns data or raises Senko::ValidationError
schema.valid_json?(json) # parses and validates a JSON string
schema.validate_json(json) # parses JSON and returns Senko::Result
One-shot helpers are also available:
Senko.valid?(schema_hash, data)
Senko.validate(schema_hash, data)
Senko.valid_json?(schema_hash, '[1, 2, 3]')
Senko.validate_json(schema_hash, '[1, 2, 3]')
Compile from a JSON file:
schema = Senko.compile_file('schema.json')
Errors and Output
validate returns a Senko::Result.
result = schema.validate({ 'name' => '' })
result.valid?
# => false
result.errors.map(&:to_h)
# => [
# {
# 'keywordLocation' => '/properties/name/minLength',
# 'instanceLocation' => '/name',
# 'error' => 'string length must be >= 1'
# }
# ]
Result objects can be rendered in JSON Schema output-style shapes:
result.to_basic
result.to_detailed
result.to_verbose
Options
Options can be passed to compile or to the one-shot helpers.
schema = Senko.compile(
schema_hash,
format: :assertion,
fail_fast: true,
validate_meta_schema: true,
codegen: :auto
)
Common options:
format: :annotationrecords format annotations without failing validation.format: :assertionmakes supported formats validation errors.fail_fast: truestops detailed validation after the first error.validate_meta_schema: truechecks schema shape before compilation.codegen: falsedisables the generated boolean fast path.messages: { type: 'custom message' }customizes built-in error messages.schemas: { uri => schema_hash }registers external schemas for$ref.
Custom Formats and Keywords
Register process-wide extensions:
Senko.register_format('starts-with-x') do |value|
value.start_with?('x-')
end
Senko.register_keyword('even') do |data, enabled|
!enabled || data.even?
end
Senko.clear_registry!
Or pass extensions to a single compiled schema:
schema = Senko.compile(
{ 'format' => 'starts-with-x' },
format: :assertion,
custom_formats: {
'starts-with-x' => ->(value) { value.start_with?('x-') }
}
)
Drafts and OpenAPI
Senko detects $schema when present and defaults to Draft 2020-12 otherwise.
It supports compatibility paths for Draft 2019-09, Draft 7, Draft 6, and
Draft 4.
Legacy and OpenAPI forms are normalized where possible:
definitions- tuple
itemsandadditionalItems dependencies- legacy
id - Draft 4 boolean exclusive numeric bounds
- OpenAPI 3.0
nullable: true
OpenAPI-style oneOf and anyOf schemas with a required const discriminator
property, or an explicit discriminator.mapping, are compiled into direct
discriminator dispatch.
Performance
valid? uses generated Ruby code when the schema is supported by the code
generator. Schemas that require full JSON Schema semantics use the interpreter.
validate always uses the interpreter so detailed errors and annotations remain
available.
Run the local performance gate:
bundle exec rake benchmark:check
The benchmark compares Senko against json_schemer across codegen,
interpreter, $ref, oneOf, and unevaluatedProperties scenarios.
Development
After checking out the repo, install dependencies:
bundle install
Gemfile.lock is intentionally ignored for this gem.
Useful commands:
bundle exec rake native:compile
bundle exec rake test
bundle exec rake suite:install
bundle exec rake suite:optional
bundle exec rake benchmark:check
bundle exec rake ci
rake ci compiles the native extension, runs the unit tests, runs the optional
JSON Schema Test Suite, checks performance, and builds the gem.
Contributing
Bug reports and pull requests are welcome. Before opening a pull request, run:
bundle exec rake ci
License
The gem is available as open source under the terms of the MIT License.