committee validates Rack requests against the schema you already publish
A collection of Rack middleware to support JSON Schema.
At a glance
- What is it?
- committee is a Ruby gem of Rack middleware that validates incoming requests against JSON Schema, OpenAPI 2 or OpenAPI 3 documents, with options for type coercion, strict path handling and per-request filtering. It sits in front of your application rather than inside it, so the specification clients read is the specification your service enforces.
- Who is it for?
- committee suits a Ruby or Rack service that already publishes an OpenAPI or JSON Schema document and wants the contract enforced at the edge of the application, and it suits teams who want validation failures to come back as structured errors rather than as model errors deep inside a controller.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One middleware, three schema dialects
Committee is described as a collection of middleware to help build services with JSON Schema, OpenAPI 2 and OpenAPI 3.
The problem it addresses is the gap between a published API contract and an application that quietly accepts anything. A service that documents its request bodies in OpenAPI 3 and then validates them by hand in each controller has two sources of truth and a good chance they disagree. This gem puts the document in the request path, so a request that does not match the specification is rejected before it reaches application code.
The RequestValidation middleware is the piece the README documents in most detail, and it is supported by all three dialects, Hyper-Schema, OpenAPI 2 and OpenAPI 3. Mounting it is one line of Rack configuration:
use Committee::Middleware::RequestValidation, schema_path: 'docs/schema.json', coerce_date_times: trueThe schema_path option defines the location of the schema file used for validation, so the document on disk is the same artifact you serve to clients.
That single line also sets the tone for the library. It is not a validation framework with its own DSL and its own vocabulary. It is middleware that reads a schema document you already have and applies it to requests. Teams that want to describe an API before writing it get little from this, while teams that already have a specification get a lot.
Coercion is where the dialects diverge
The option table is long, and the interesting part is that some options have different defaults under Hyper-Schema and OpenAPI 3. Coercion is where that matters most.
Under OpenAPI 3, coerce_date_times is on by default and converts a string with a format of date-time into a DateTime object. Under Hyper-Schema and OpenAPI 2 it is off. The same split applies to coerce_form_params, coerce_path_params and coerce_query_params, which are all true for OpenAPI 3 and false for the older dialects, except that in Hyper-Schema and OpenAPI 2 coerce_form_params is primarily used for application/x-www-form-urlencoded bodies, while in OpenAPI 3 the option is used for request body validation more generally, including application/json bodies.
What coercion actually does is narrow and predictable. It converts request body values into the concrete types the schema requires, and it works for null as an empty value, integer as a numeric value without decimals, number as a numeric value and boolean, where the string true becomes true and false becomes false. If coercion is not possible, the original value is passed unchanged to schema validation. That last clause is the one to remember, because a body that was meant to be coerced can reach validation uncoerced and fail there rather than being rejected early with a clear message.
Two options are always on for OpenAPI 3: allow_blank_structures, which allows an empty response body, and coerce_recursive, which coerces data in arrays and other nested objects.
The coerce_path_params and coerce_query_params options extend the same behaviour to URL path parameters and query string parameters, which matters for APIs that take identifiers as strings in the path and expect integers downstream.
Strict mode, query parameters and unresolvable references
A validation middleware has to decide what to do with requests the schema does not describe, and Committee makes those decisions configurable rather than implicit.
The strict option puts the middleware into strict mode, meaning that paths which are not defined in the schema are responded to with a 404 instead of being run. This is the option that turns a validator into a contract enforcer, and it is off by default, which is the safer starting point for an existing service with routes the document does not mention.
strict_query_params rejects requests with query parameters not defined in the schema, and any query parameter not explicitly defined in the OpenAPI specification results in a 400 error. The README lists this option as not supported on the Hyper-Schema parser.
strict_reference_validation raises an exception, OpenAPIParser::MissingReferenceError, when the middleware loads if the provided schema file contains unresolvable references such as a $ref pointing at a path that does not exist. It is not supported on the Hyper-Schema parser, and it defaults to false on OpenAPI 3 while the README says it will default to true in the next major version. That is a sensible default to move towards, since a broken reference in a schema is a bug in the document rather than a runtime condition to be discovered in production.
The looser options form the other side of the ledger. allow_form_params lets input be specified as application/x-www-form-urlencoded parameters when possible, with the caveat that this will not work for more complex schema validations. allow_get_body allows a GET request body, which merges into the request parameter. allow_query_params takes query string parameters into consideration during validation, and allow_non_get_query_params extends that to non-GET requests. check_content_type verifies the Content-Type against the schema definition, and check_header checks header data against it.
Error handling and where the validated data ends up
A validator is only useful if the application downstream can trust what it receives, and Committee does that by writing the checked and merged values into the Rack environment.
Five keys control where that data lands. params_key saves the checked and merged parameter value, defaulting to committee.params. headers_key saves the checked header value, defaulting to committee.headers. path_hash_key saves the checked path parameter value, defaulting to committee.path_hash. request_body_hash_key saves the checked request body parameters for JSON and form bodies, defaulting to committee.request_body_hash, and for other OpenAPI 3 content types the value is the raw body string and is not merged into params_key. query_hash_key defaults to rack.request.query_hash, though the README says it will change to committee.query_hash in the next version.
Errors are configurable too. The raise option makes the middleware raise an exception instead of responding with a generic error body. error_class changes the class of the validation error, and error_handler is a proc called when an error occurs, taking the error instance as its first argument and request.env as its second, with the README's example capturing the exception into an error reporting service.
The error body is structured. The example in the README shows a failed request returning a JSON document with an id of bad_request and a message that names the failing location in the schema and the missing parameter, which is a much more useful thing to hand back to a client than a generic rejection.
One more option is worth singling out: accept_request_filter is a proc that accepts a request and returns a boolean, indicating whether to validate the current request or not. That is how you apply validation to part of an API rather than all of it, such as health checks or a legacy path.
Ruby versions, packaging and the defaults that are about to move
Committee is a gem with a conventional Ruby repository layout: a committee.gemspec, a Gemfile, a Rakefile, a.ruby-version file,.rubocop.yml, bin/, lib/, test/, and a CHANGELOG.md, CONTRIBUTING.md, CONTRIBUTORS.md and SECURITY.md at the top level.
The examples directory is the most useful part of the layout for evaluation, because it contains four separate applications rather than one. There is examples/heroku_api/, examples/json_schema/, examples/openapi3/ and examples/openapi3_rails/. Between them they cover the three schema dialects the README mentions and two hosting models, a plain Rack service and a Rails application. Reading the one closest to your stack is faster than reconstructing the wiring from the option table.
The supported Ruby versions are listed explicitly. Committee is tested on MRI 2.7, 3.0, 3.1, 3.2, 3.3, 3.4 and 4.0, which is a wide range and includes the newest major version.
Now the thing to watch. Several defaults are documented as changing in the next major version, and three of them can change behaviour rather than just configuration. allow_blank_structures is supported on the Hyper-Schema parser and will default to true in the next major version. strict_reference_validation defaults to false on OpenAPI 3 and will default to true. And query_hash_key currently defaults to rack.request.query_hash and will change to committee.query_hash.
The last two matter if your code reads those environment keys directly. A gem upgrade that moves a default is the kind of change that surfaces as a subtle bug in a controller rather than as an error, so pin the version until you have migrated.
The licence is MIT, and the last push to the repository was on 2026-10-17 with no GitHub releases, so there is no tagged version to pin to and you would be installing from the released gem.
Editorial conclusion
committee suits a Ruby or Rack service that already publishes an OpenAPI or JSON Schema document and wants the contract enforced at the edge of the application, and it suits teams who want validation failures to come back as structured errors rather than as model errors deep inside a controller. It is the wrong choice for a service with no schema to enforce, and the wrong choice when validation belongs to a gateway that sits in front of every service rather than to one of them. Before you mount it, read the option table against your schema dialect, because several options behave differently under Hyper-Schema and OpenAPI 3, and note that the gem's own defaults are scheduled to change, with allow_blank_structures, strict_reference_validation and the query hash key all listed as changing in the next major version.
Frequently asked questions
How do I add JSON Schema validation to a Rack application with committee?
Mount the RequestValidation middleware with a schema path, for example use Committee::Middleware::RequestValidation, schema_path: 'docs/schema.json', coerce_date_times: true. The schema_path option defines the location of the schema file used for validation.
Which schema formats does the committee gem support?
Committee is a collection of middleware to help build services with JSON Schema, OpenAPI 2 and OpenAPI 3. The RequestValidation middleware is supported by all three, and Hyper-Schema and OpenAPI 2 share the same defaults for options.
What does the strict option do in committee?
It puts the middleware into strict mode, so paths that are not defined in the schema are responded to with a 404 instead of being run. A separate strict_query_params option rejects query parameters the OpenAPI specification does not define with a 400 error.
Which Ruby versions does committee support?
Committee is tested on MRI versions 2.7, 3.0, 3.1, 3.2, 3.3, 3.4 and 4.0. The repository ships a committee.gemspec, a Rakefile, a .ruby-version file and examples for JSON Schema, OpenAPI 3, a Heroku API and a Rails application.
Are any committee defaults changing in a future release?
Yes. The README states that allow_blank_structures and strict_reference_validation will default to true in the next major version, and that query_hash_key will change from rack.request.query_hash to committee.query_hash. Pin the gem version until you have migrated to those keys.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/interagent-committee)Was this useful?