<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Manan Kanani</title>
    <description>The latest articles on Forem by Manan Kanani (@manankanani).</description>
    <link>https://forem.com/manankanani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1274335%2Ff1ba0a9b-8d00-4762-873a-f4624614ddd9.png</url>
      <title>Forem: Manan Kanani</title>
      <link>https://forem.com/manankanani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/manankanani"/>
    <language>en</language>
    <item>
      <title>The Problem No One Talks About in Prisma APIs</title>
      <dc:creator>Manan Kanani</dc:creator>
      <pubDate>Sat, 17 Jan 2026 08:49:21 +0000</pubDate>
      <link>https://forem.com/manankanani/the-problem-no-one-talks-about-in-prisma-apis-npc</link>
      <guid>https://forem.com/manankanani/the-problem-no-one-talks-about-in-prisma-apis-npc</guid>
      <description>&lt;p&gt;Prisma has made SQL database access in Node.js incredibly clean.&lt;/p&gt;

&lt;p&gt;Schemas are readable.&lt;br&gt;
Type safety is excellent.&lt;br&gt;
Queries feel intuitive.&lt;/p&gt;

&lt;p&gt;But after building a few real-world APIs with Prisma, I ran into a problem that no one really talks about.&lt;/p&gt;

&lt;p&gt;Not performance.&lt;br&gt;
Not migrations.&lt;br&gt;
Not relations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repetitive query logic.&lt;/strong&gt;&lt;br&gt;
And once you see it, you can’t unsee it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Part Everyone Accidentally Rebuilds
&lt;/h2&gt;

&lt;p&gt;Every Prisma API starts the same way.&lt;/p&gt;

&lt;p&gt;A simple &lt;code&gt;findMany&lt;/code&gt;.&lt;br&gt;
A couple of filters.&lt;br&gt;
One search field.&lt;/p&gt;

&lt;p&gt;Then requirements grow.&lt;/p&gt;

&lt;p&gt;Now the endpoint needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;filtering
&lt;/li&gt;
&lt;li&gt;searching
&lt;/li&gt;
&lt;li&gt;sorting
&lt;/li&gt;
&lt;li&gt;pagination
&lt;/li&gt;
&lt;li&gt;soft delete checks
&lt;/li&gt;
&lt;li&gt;query validation
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you add a few &lt;code&gt;if&lt;/code&gt; statements.&lt;br&gt;
You write something like this in one service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And suddenly every endpoint has its own slightly different version of the same logic.&lt;/p&gt;

&lt;p&gt;Not because you planned it that way - but because Prisma doesn't give you an opinion here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Copy-Paste Is Easy. Living With It Isn’t.
&lt;/h2&gt;

&lt;p&gt;At first, duplication feels fine.&lt;/p&gt;

&lt;p&gt;But over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one endpoint allows invalid filters
&lt;/li&gt;
&lt;li&gt;another rejects them
&lt;/li&gt;
&lt;li&gt;one sorts on any column
&lt;/li&gt;
&lt;li&gt;another breaks if you try
&lt;/li&gt;
&lt;li&gt;one handles booleans correctly
&lt;/li&gt;
&lt;li&gt;another treats everything as a string
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing is technically broken.&lt;br&gt;
But nothing feels solid either.&lt;/p&gt;

&lt;p&gt;This is how small inconsistencies turn into long debugging sessions.&lt;/p&gt;


&lt;h2&gt;
  
  
  Helpers Don’t Actually Fix This
&lt;/h2&gt;

&lt;p&gt;The obvious move is a helper function.&lt;/p&gt;

&lt;p&gt;Most teams try it.&lt;br&gt;
Most teams regret it.&lt;/p&gt;

&lt;p&gt;Helpers tend to become:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;too flexible to be safe
&lt;/li&gt;
&lt;li&gt;too strict to be reusable
&lt;/li&gt;
&lt;li&gt;hard to reason about
&lt;/li&gt;
&lt;li&gt;impossible to extend cleanly
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And many of them go one step too far — they &lt;strong&gt;run the Prisma query for you&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s when your service layer starts losing control.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Shift That Changed Everything
&lt;/h2&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I share this logic?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why is this logic even being written repeatedly?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every endpoint already knows its rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what can be filtered
&lt;/li&gt;
&lt;li&gt;what can be searched
&lt;/li&gt;
&lt;li&gt;what can be sorted
&lt;/li&gt;
&lt;li&gt;what should be rejected
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the real problem wasn’t queries.&lt;/p&gt;

&lt;p&gt;It was &lt;strong&gt;encoding intent&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Declare Rules. Get a Prisma Query.
&lt;/h2&gt;

&lt;p&gt;That idea became &lt;strong&gt;Prisma Query Builder (&lt;code&gt;prisma-qb&lt;/code&gt;)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of hand-writing query logic, you configure rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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" }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What comes out is not data — just a &lt;strong&gt;safe Prisma query object&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Prisma &lt;code&gt;where&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A Prisma &lt;code&gt;orderBy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No execution.&lt;br&gt;
No abstraction.&lt;br&gt;
No opinion about how you fetch.&lt;/p&gt;

&lt;p&gt;Your service stays boring — in the best way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Strict by Default (And That’s the Point)
&lt;/h2&gt;

&lt;p&gt;Most bugs here don’t come from bad code.&lt;/p&gt;

&lt;p&gt;They come from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unexpected query params
&lt;/li&gt;
&lt;li&gt;invalid filters
&lt;/li&gt;
&lt;li&gt;unchecked sorts
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prisma Query Builder blocks those immediately.&lt;/p&gt;

&lt;p&gt;Not silently.&lt;br&gt;
Not later.&lt;br&gt;
&lt;strong&gt;Immediately.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API becomes predictable — not just for users, but for developers too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Search That Doesn’t Break Your API
&lt;/h2&gt;

&lt;p&gt;Search is where most APIs quietly fail.&lt;/p&gt;

&lt;p&gt;Numbers get treated like strings.&lt;br&gt;
Booleans behave unpredictably.&lt;br&gt;
One bad field breaks the whole query.&lt;/p&gt;

&lt;p&gt;Here, search is type-aware.&lt;/p&gt;

&lt;p&gt;Valid fields participate.&lt;br&gt;
Invalid ones are skipped safely.&lt;br&gt;
Nothing crashes.&lt;br&gt;
Nothing leaks through.&lt;/p&gt;

&lt;p&gt;Your API stays stable even with messy input.&lt;/p&gt;




&lt;h2&gt;
  
  
  This Isn’t a Prisma Replacement
&lt;/h2&gt;

&lt;p&gt;It doesn’t:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wrap Prisma
&lt;/li&gt;
&lt;li&gt;hide Prisma
&lt;/li&gt;
&lt;li&gt;execute Prisma
&lt;/li&gt;
&lt;li&gt;invent new query concepts
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It simply builds Prisma queries responsibly.&lt;/p&gt;

&lt;p&gt;You still own the data.&lt;br&gt;
You still own the execution.&lt;br&gt;
You still own the architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who This Is For
&lt;/h2&gt;

&lt;p&gt;This is for people who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build real APIs, not demos
&lt;/li&gt;
&lt;li&gt;care about long-term consistency
&lt;/li&gt;
&lt;li&gt;hate rewriting the same logic
&lt;/li&gt;
&lt;li&gt;want services that stay readable over time
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If that sounds familiar, you’ve already felt this problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;Prisma solved database access.&lt;/p&gt;

&lt;p&gt;But API-level query handling is still left to repetition, habits, and copy-paste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prisma Query Builder exists to remove that noise.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And once it’s gone,&lt;br&gt;
your API feels calmer — and stays that way.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;npm&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/prisma-qb" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/prisma-qb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it and hate it, tell me.&lt;br&gt;
If you like it, tell me.&lt;/p&gt;

&lt;p&gt;Either way — that’s how better tools get built 😉&lt;/p&gt;

</description>
      <category>npm</category>
      <category>prisma</category>
      <category>node</category>
      <category>productivity</category>
    </item>
    <item>
      <title>blur background moving with cursor on a particular div</title>
      <dc:creator>Manan Kanani</dc:creator>
      <pubDate>Tue, 06 Feb 2024 09:15:27 +0000</pubDate>
      <link>https://forem.com/manankanani/blur-background-moving-with-cursor-on-a-particular-div-58lg</link>
      <guid>https://forem.com/manankanani/blur-background-moving-with-cursor-on-a-particular-div-58lg</guid>
      <description>&lt;p&gt;blur background moving with cursor on a particular div&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/manankanani/embed/zYbaErz?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>codepen</category>
    </item>
  </channel>
</rss>
