Hey folks!
I built FlopRest, a small library that transforms Stripe-style query parameters into Flop format.
The Problem
Flop is excellent for filtering, sorting, and paginating Ecto queries. But when building JSON APIs, its native format creates friction:
?filters[0][field]=status&filters[0][op]==&filters[0][value]=published&filters[1][field]=starts_at&filters[1][op]=>=&filters[1][value]=2024-01-01&order_by[0]=starts_at&order_directions[0]=desc&first=20
Frontend developers expect something like Stripe or GitHub:
?status=published&starts_at[gte]=2024-01-01&sort=-starts_at&limit=20
Same query. FlopRest bridges that gap—same Flop power underneath, better DX on top.
Usage
def index(conn, params) do
flop_params = FlopRest.normalize(params)
with {:ok, {events, meta}} <- Flop.validate_and_run(Event, flop_params, for: Event) do
json(conn, %{
data: events,
links: %{
self: FlopRest.build_path(conn.request_path, meta.flop),
next: meta.has_next_page? && FlopRest.build_path(conn.request_path, meta.next_flop),
prev: meta.has_previous_page? && FlopRest.build_path(conn.request_path, meta.previous_flop)
}
})
end
end
What It Supports
- Filters:
status=published,amount[gte]=100 - Sorting:
sort=-created_at,name(minus for desc) - Pagination: Cursor (
limit+starting_after), page-based, and offset-based - Pagination links:
build_path/2generatesnext/prevURLs from Flop meta
All 21 Flop operators are supported.
When to Use It
Building a LiveView/HTML app? Flop Phoenix already handles the UI side.
Building a JSON API consumed by React/Vue/Svelte/mobile apps? FlopRest makes your API feel native to frontend developers—standard URLSearchParams just works, no custom serialization needed.
Design
Pure transformation layer. Invalid params pass through for Flop to validate.






















