A Rails integration for json_schemer that provides OpenAPI 3.0 request validation and parameter type casting for your Rails controllers.
- ✅ Validates request bodies against OpenAPI 3.0 schemas
- ✅ Validates path and query parameters
- ✅ Automatic type casting for query parameters (strings to booleans, integers, etc.)
- ✅ Schema references (
$ref) support - ✅ Content-Type validation
- ✅ Comprehensive error messages
- ✅ Easy integration with Rails controllers
Add this line to your application's Gemfile:
gem 'json_schemer-rails'And then execute:
bundle installCreate an openapi.yml file in your Rails root directory:
openapi: 3.0.0
info:
title: My API
version: 1.0.0
paths:
/users:
post:
summary: Create a user
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
email:
type: string
format: email
age:
type: integer
required:
- name
- email
parameters:
- name: notify
in: query
schema:
type: boolean
responses:
'201':
description: User created
/users/{id}:
get:
summary: Get a user
parameters:
- name: id
in: path
required: true
schema:
type: string
pattern: '^[0-9]+$'
responses:
'200':
description: User detailsclass UsersController < ApplicationController
include JSONSchemer::Rails::Controller
before_action :validate_from_openapi, only: [:create, :update]
def create
# At this point:
# - Request body has been validated against the schema
# - Query parameters have been type-cast (e.g., "true" → true)
# - Path parameters have been validated
user = User.create!(params.permit(:name, :email, :age))
render json: user, status: :created
end
endclass UsersController < ApplicationController
def create
validator = JSONSchemer::Rails::OpenApiValidator.new(request)
# Validate and cast parameters
validator.validated_params
# Validate request body
errors = validator.validate_body.to_a
if errors.any?
render json: { errors: errors }, status: :unprocessable_entity
return
end
user = User.create!(params.permit(:name, :email, :age))
render json: user, status: :created
end
endBy default, the validator looks for openapi.yml in your Rails root. You can specify a different location:
validator = JSONSchemer::Rails::OpenApiValidator.new(
request,
open_api_filename: Rails.root.join('config', 'api_schema.yml')
)The validator automatically:
- Checks that the
Content-Typeheader is set toapplication/jsonfor POST/PUT/PATCH requests - Parses the request body as JSON
- Validates the JSON against the schema defined in your OpenAPI spec
- Returns detailed validation errors if the body doesn't match the schema
The validator processes both query and path parameters:
- Type Casting: Converts string values to their specified types
"true","1"→true"false","0"→false- Numbers are cast to integers/floats as specified
- Validation: Ensures parameters match their schema definitions
- Unknown Parameters: Ignores parameters not defined in the OpenAPI spec
- Validates against schema patterns (e.g., regex patterns)
- Validates against referenced schemas (
$ref) - Raises
RequestValidationErrorif validation fails
Given this OpenAPI parameter definition:
parameters:
- name: notify
in: query
schema:
type: boolean
- name: limit
in: query
schema:
type: integerQuery string: ?notify=true&limit=10
Before validation:
params[:notify] # => "true" (String)
params[:limit] # => "10" (String)After validated_params:
params[:notify] # => true (Boolean)
params[:limit] # => "10" (String, not cast because OpenAPI handles this differently)When validation fails, a JSONSchemer::Rails::RequestValidationError is raised:
class ApplicationController < ActionController::API
rescue_from JSONSchemer::Rails::RequestValidationError do |exception|
render json: { error: exception.message }, status: :unprocessable_entity
end
endThe gem includes comprehensive RSpec tests. To run the test suite:
bundle exec rspecUse ActionDispatch::TestRequest to test your validated endpoints:
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
describe 'POST #create' do
it 'validates the request body' do
request.headers['Content-Type'] = 'application/json'
post :create, body: { name: 'John', email: 'john@example.com' }.to_json
expect(response).to have_http_status(:created)
end
it 'rejects invalid requests' do
request.headers['Content-Type'] = 'application/json'
post :create, body: { name: 'John' }.to_json # missing email
expect(response).to have_http_status(:unprocessable_entity)
end
end
endclass UsersController < ApplicationController
include JSONSchemer::Rails::Controller
before_action :validate_from_openapi, except: [:index]
def index
# No validation needed for GET requests without body
end
def create
# Validated automatically
end
endclass UsersController < ApplicationController
def create
validator = JSONSchemer::Rails::OpenApiValidator.new(request)
# Validate parameters first
validator.validated_params
# Then validate body
body_errors = validator.validate_body.to_a
# Add custom validation
custom_errors = custom_business_logic_validation
all_errors = body_errors + custom_errors
if all_errors.any?
render json: { errors: all_errors }, status: :unprocessable_entity
return
end
# Proceed with valid data
end
private
def custom_business_logic_validation
# Your custom validation logic
[]
end
end- Ruby >= 3.4.0
- Rails >= 8.0
- json_schemer >= 2.5
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install.
Bug reports and pull requests are welcome on GitHub at https://github.com/sul-dlss/json_schemer-rails.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request
The gem is available as open source under the terms of the MIT License.
Built with json_schemer by Davis W. McGuire.
Developed by Stanford Digital Library.