api_query_language
A filter and sort query-language parser for JSON APIs. Parses URL query
expressions like ?filter=status:active&sort=created_at:desc into a structured
AST. Zero ActiveSupport, zero ActiveRecord.
Part of the another_api family.
For the ActiveRecord-aware variant that produces real AR/Arel queries, see
api_query_language-active_record.
Installation
gem "api_query_language"
Runtime dependencies: literal and
racc. racc ships a C extension when
available and falls back to a pure-Ruby implementation otherwise.
Development-only: oedipus_lex
and racc itself are used to generate the checked-in .rex.rb / .y.rb
artefacts. Runtime does not require oedipus_lex; you only need it if you
change a .rex or .y grammar and run bundle exec rake generate from
this directory.
Quickstart
expr = ApiQueryLanguage::Filtering::FilterExpression.new(
"status:active [and] created_at{gte}:2024-01-01",
{ status: nil, created_at: nil }
)
expr.ast_root
# => Parsed AST — walk it with your own visitor to produce queries for any
# backend (ActiveRecord, Sequel, Elasticsearch, etc.).
sort = ApiQueryLanguage::Sorting::SortExpression.new(
"created_at:desc;name:asc",
{ created_at: nil, name: nil }
)
sort.parsed
# => Parsed sort AST — SortExpression exposes `#parsed` rather than
# `#ast_root` because the AST shape is flatter.
Input is hard-capped at 1000 characters; longer expressions raise
Errors::InvalidExpressionError before they reach the lexer.
Filter syntax
field:value equality (parses to a plain Field node)
field{eq}:value equality (parses to a FieldComparison node —
same result, different AST shape, useful if
your visitor handles comparisons uniformly)
field{gte}:value comparison (eq, neq, gt, gte, lt, lte, ieq)
field:a|b|c OR across values
field:a&b AND across values
name:a* / name:*a / name:*a* wildcards — `*` matches any, `+` matches one
or more (e.g. `name:a+` = at least one char
after `a`)
null(field) / NULL(field) matches rows where `field IS NULL`
[not] field:value negation (also wraps groups: `[not] (…)`)
field:a [and] field:b logical composition
(field:a [or] field:b) [and] … grouping
Values are URL-decoded before the lexer sees them: field:testy%40example.com
resolves to field:testy@example.com. Use %25 for a literal %.
Sort syntax
field:asc ascending
field:desc descending
field1:asc;field2:desc multiple fields (separator is `;`)
License
MIT. See LICENSE.txt at the repository root.