Express
Parse req.query into validated pagination params. The adapter is
framework-agnostic — it only needs an object of query values, so it also fits
Fastify, Koa, and URLSearchParams (via Object.fromEntries). The
parsed OffsetParams / CursorParams are validated by the Rust core, so the
range and exclusivity rules match every other package — see
cross-language parity.
Install
npm i @cyblow/paginate
import { express, paginate } from "@cyblow/paginate";
Public API
// { page, limit } from the query (validated; throws ValidationError if bad)
express.offsetParamsFromQuery(query: QueryLike): OffsetParams;
// { limit, after?, before? } from the query (after/before mutually exclusive)
express.cursorParamsFromQuery(query: QueryLike): CursorParams;
QueryLike is Record<string, string | string[] | undefined> — Express's
req.query shape. Missing or empty values fall back to the defaults
(page=1, limit=20). When a query value is an array, the first element wins.
Offset endpoint
Parse the params, then paginate your data. For an in-memory array, hand the
params straight to paginate (identical results to pypaginate — see
parity):
import express from "express";
import { express as paginateExpress, paginate, ValidationError } from "@cyblow/paginate";
const app = express();
app.get("/users", (req, res) => {
try {
const params = paginateExpress.offsetParamsFromQuery(req.query);
const page = paginate(users, params, {
filters: [{ field: "status", operator: "eq", value: "active" }],
sorting: [{ field: "created_at", direction: "desc" }],
});
res.json({ items: page.items, total: page.total, pages: page.pages });
} catch (err) {
if (err instanceof ValidationError) {
return res.status(400).json({ error: err.message });
}
throw err;
}
});
Cursor endpoint
cursorParamsFromQuery reads ?limit=&after=&before= (passing both after and
before throws ValidationError). In-memory keyset pagination is not supported —
forward the parsed CursorParams to a database adapter such as
Prisma or Drizzle:
app.get("/posts", async (req, res) => {
const params = paginateExpress.cursorParamsFromQuery(req.query);
const { items, nextCursor } = await page(params); // your Prisma/Drizzle keyset query
res.json({ items, nextCursor });
});
Other frameworks
Any object of query values works. With the WHATWG URLSearchParams (Fetch /
Koa / Fastify), convert first:
const url = new URL(request.url);
const params = paginateExpress.offsetParamsFromQuery(Object.fromEntries(url.searchParams));