The Problem No One Talks About in Prisma APIs
Source: Dev.to
The Repetitive Query Logic Problem
As requirements grow, endpoints need:
- filtering
- searching
- sorting
- pagination
- soft‑delete checks
- query validation
Typical ad‑hoc solutions look like this:
if (query.isActive) {
where.isActive = query.isActive === "true";
}
if (query.search) {
where.OR = [
{ firstName: { contains: query.search, mode: "insensitive" } },
{ email: { contains: query.search, mode: "insensitive" } }
];
}
if (query.sort === "createdAt") {
orderBy.createdAt = "desc";
}
Every endpoint ends up with its own slightly different version of the same logic.
At first the duplication feels harmless, but over time you get:
- one endpoint allowing invalid filters, another rejecting them
- inconsistent sorting behavior
- booleans handled correctly in some places, treated as strings elsewhere
These small inconsistencies lead to long debugging sessions even though nothing is technically broken.
Why Simple Helpers Aren’t Enough
A common reaction is to extract the repeated code into a helper function. In practice, helpers often become:
- Too flexible – unsafe and hard to reason about
- Too strict – not reusable across different endpoints
- Hard to extend – brittle when new requirements appear
Some helpers even execute the Prisma query for you, causing the service layer to lose control over execution flow.
Encoding Intent Instead of Repeating Logic
The real issue isn’t the queries themselves; it’s the lack of a clear way to encode intent—what can be filtered, searched, sorted, or rejected.
Enter Prisma Query Builder (prisma‑qb), a tiny library that lets you configure those rules once and generate a safe Prisma query object.
Usage Example
import { buildPrismaQuery } from "prisma-qb";
const { where, orderBy } = buildPrismaQuery({
query: req.query,
searchFields: [
{ field: "firstName" },
{ field: "email" }
],
filterFields: [
{ key: "isActive", field: "isActive", type: "boolean" }
],
sortFields: [
{ key: "createdAt", field: "createdAt" }
],
defaultSort: { key: "createdAt", order: "desc" }
});
The function returns only the Prisma where and orderBy objects—no execution. Your service layer remains in charge of actually running the query.
Benefits
- Predictable API – invalid query params, unexpected filters, and unchecked sorts are blocked immediately.
- Type‑aware searching – numbers aren’t mistakenly treated as strings.
- No hidden execution – the library never runs Prisma for you, so you keep full control.
- Stable with messy input – only the fields you explicitly allow participate in the query.
It doesn’t wrap Prisma, hide it, or invent new query concepts; it simply builds Prisma queries responsibly.
Who Should Use It?
- Developers building real APIs, not just demos
- Teams that care about long‑term consistency
- Anyone who hates rewriting the same logic across endpoints
- Projects that need services to stay readable and maintainable over time
If this sounds familiar, you’ve likely already felt the pain of repetitive query handling. Prisma solved database access; Prisma Query Builder tackles the remaining API‑level duplication.
Get It
Give it a try, and if you don’t like it, let me know. Feedback helps build better tools. 😉