<?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>DEV Community: Rizqy Eka Putra</title>
    <description>The latest articles on DEV Community by Rizqy Eka Putra (@rizqyep).</description>
    <link>https://dev.to/rizqyep</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%2F466091%2F101f571e-bbb7-47b5-9be0-6f3626c64797.jpeg</url>
      <title>DEV Community: Rizqy Eka Putra</title>
      <link>https://dev.to/rizqyep</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rizqyep"/>
    <language>en</language>
    <item>
      <title>Easily Create an XLSX Output by Using Only HTML Table Component</title>
      <dc:creator>Rizqy Eka Putra</dc:creator>
      <pubDate>Sat, 30 Aug 2025 17:02:21 +0000</pubDate>
      <link>https://dev.to/rizqyep/easily-create-an-xlsx-output-by-using-only-html-table-component-2iak</link>
      <guid>https://dev.to/rizqyep/easily-create-an-xlsx-output-by-using-only-html-table-component-2iak</guid>
      <description>&lt;h2&gt;
  
  
  TLDR; The Origin Story
&lt;/h2&gt;

&lt;p&gt;So, recently while i work on my weekend projects, as well in some projects with my team at &lt;a href="https://nodewave.id" rel="noopener noreferrer"&gt;Nodewave&lt;/a&gt;, there are a significant amount of time (and pains...) consumed when we need to generate a structured XLSX with complex tables that has merged cells (row, columns). Before, we are always writing a custom excel builder with &lt;code&gt;xlsx-js-style&lt;/code&gt; for EVERY single XLSX file output, which you can already tell must be really time consuming, nevermind the back and forth to check the result while testing it.&lt;/p&gt;

&lt;p&gt;Then, in a discussion, we came with an idea, why not write it with a &lt;code&gt;table&lt;/code&gt; components in HTML, which natively already has &lt;code&gt;colspan&lt;/code&gt;, &lt;code&gt;rowspan&lt;/code&gt; attribute, and also has &lt;code&gt;inline-css&lt;/code&gt; for the styling. &lt;/p&gt;

&lt;p&gt;As a bunch of curious engineers we started to get going by discussing it with an expert every developer's reach out whenever they have a new idea (TLDR; AI) 🤖. &lt;/p&gt;

&lt;p&gt;Initially, all we wanted to do is just to parse an html table that contains &lt;code&gt;rowspan&lt;/code&gt; and &lt;code&gt;colspan&lt;/code&gt; attributes, process it with &lt;code&gt;cheerio&lt;/code&gt; feed it into a custom function that builds excel rows with &lt;code&gt;xlsx-js-style&lt;/code&gt; and call it a day.&lt;/p&gt;

&lt;p&gt;But then again, we came to think, why not also take care of the styling, &lt;code&gt;xlsx-js-style&lt;/code&gt; has the capability to set various things like &lt;code&gt;background color&lt;/code&gt; , &lt;code&gt;text color&lt;/code&gt; and many more. &lt;/p&gt;

&lt;p&gt;So in a span of just several hours, we already came with &lt;strong&gt;4 Minor VERSIONS&lt;/strong&gt; of the library. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;v0.1.0 -&amp;gt; Basic HTML table processor, which have a separate title config (we removed this immediately later on)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v0.1.1 -&amp;gt; Some small refactors &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v0.1.2 -&amp;gt; Yet again another refactors, to handle title within the conversion process &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;v0.2.0 -&amp;gt; Handles inline CSS&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, without further ado, we presents you &lt;code&gt;@nodewave/table-to-xlsx&lt;/code&gt; , the idea is simple, it takes an html table in a string, then returns an excel corresponding of that tables, we support 2 output mode : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Buffer Mode&lt;/li&gt;
&lt;li&gt;File Output Mode.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Let's See It In Action! 🚀
&lt;/h2&gt;

&lt;p&gt;Now that we've covered the origin story, let me showcase the incredible capabilities of our &lt;code&gt;@nodewave/table-to-xlsx&lt;/code&gt; package with some real-world examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;Basic Usage - Simple Table Conversion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's start with the basics. Here's how simple it is to convert a basic HTML table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;convert&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nodewave/table-to-xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simpleTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;table&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;Age&amp;lt;/th&amp;gt;
        &amp;lt;th&amp;gt;City&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;John Doe&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;30&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;New York&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;Jane Smith&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;25&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Los Angeles&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
`&lt;/span&gt;

&lt;span class="c1"&gt;// Convert to buffer (in-memory)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simpleTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Or save directly to file&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simpleTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./employees.xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔥 &lt;strong&gt;Advanced Features - Merged Cells &amp;amp; Complex Layouts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is where our package truly shines! Let's create a complex table with merged cells that would be a nightmare to build manually with Excel APIs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;complexTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;table&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; font-size: 18px; text-align: center;" colspan="6"&amp;gt;
            🏢 Company Financial Report Q4 2024
        &amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="6"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th style="background-color: #F8F9FA; font-weight: bold;" rowspan="2"&amp;gt;Department&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #F8F9FA; font-weight: bold;" rowspan="2"&amp;gt;Team&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #F8F9FA; font-weight: bold; text-align: center;" colspan="2"&amp;gt;Q3 Results&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #F8F9FA; font-weight: bold; text-align: center;" colspan="2"&amp;gt;Q4 Results&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th style="background-color: #E9ECEF; text-align: center;"&amp;gt;Revenue&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #E9ECEF; text-align: center;"&amp;gt;Growth&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #E9ECEF; text-align: center;"&amp;gt;Revenue&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #E9ECEF; text-align: center;"&amp;gt;Growth&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold; color: #2E86AB;"&amp;gt;Engineering&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Backend Team&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$2.5M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+15%&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$2.9M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+16%&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold; color: #2E86AB;"&amp;gt;Engineering&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Frontend Team&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$1.8M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+12%&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$2.1M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+17%&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold; color: #2E86AB;"&amp;gt;Sales&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Enterprise&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$5.2M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+8%&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$5.8M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+12%&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold; color: #2E86AB;"&amp;gt;Sales&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;SMB&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #FFC107;"&amp;gt;$1.2M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #FFC107;"&amp;gt;-3%&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; color: #28A745;"&amp;gt;$1.4M&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center; color: #28A745;"&amp;gt;+17%&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="6"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th style="background-color: #D4EDDA; color: #155724; font-size: 16px; text-align: center;" colspan="6"&amp;gt;
            📈 Total Q4 Revenue: $12.2M (+15% YoY)
        &amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
`&lt;/span&gt;

&lt;span class="c1"&gt;// Convert this complex table with merged cells and styling&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;complexTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./financial-report.xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🎨 &lt;strong&gt;Styling Capabilities - CSS Classes &amp;amp; Inline Styles&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our package supports both inline CSS and CSS classes, making it incredibly flexible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styledTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;table&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th class="header-cell text-center font-bold" style="background-color: #6C757D; color: white; font-size: 20px;" colspan="4"&amp;gt;
            🎯 Product Performance Dashboard
        &amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="4"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th class="subheader text-left font-bold" style="background-color: #F8F9FA;"&amp;gt;Product Name&amp;lt;/th&amp;gt;
        &amp;lt;th class="subheader text-center font-bold" style="background-color: #F8F9FA;"&amp;gt;Category&amp;lt;/th&amp;gt;
        &amp;lt;th class="subheader text-center font-bold" style="background-color: #F8F9FA;"&amp;gt;Sales&amp;lt;/th&amp;gt;
        &amp;lt;th class="subheader text-center font-bold" style="background-color: #F8F9FA;"&amp;gt;Rating&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="color: #2E86AB; font-weight: bold;"&amp;gt;🚀 Product A&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-center"&amp;gt;Software&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-right font-bold" style="color: #28A745;"&amp;gt;$125K&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-center font-bold" style="background-color: #D4EDDA; color: #155724;"&amp;gt;⭐⭐⭐⭐⭐&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="color: #2E86AB; font-weight: bold;"&amp;gt;💡 Product B&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-center"&amp;gt;Hardware&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-right font-bold" style="color: #28A745;"&amp;gt;$89K&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-center font-bold" style="background-color: #D4EDDA; color: #155724;"&amp;gt;⭐⭐⭐⭐&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="color: #2E86AB; font-weight: bold;"&amp;gt;🔧 Product C&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-center"&amp;gt;Service&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-right font-bold" style="color: #FFC107;"&amp;gt;$67K&amp;lt;/td&amp;gt;
        &amp;lt;td class="text-center font-bold" style="background-color: #FFF3CD; color: #856404;"&amp;gt;⭐⭐⭐&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
`&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styledTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./product-dashboard.xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📊 &lt;strong&gt;Real-World Use Case - Invoice Table&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here's a practical example of an invoice table that demonstrates complex merging and professional styling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invoiceTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;table&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none; font-size: 24px; font-weight: bold; color: #2E86AB;" colspan="6"&amp;gt;
            �� NODEWAVE TECHNOLOGIES
        &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none; font-size: 14px; color: #6C757D;" colspan="6"&amp;gt;
            123 Innovation Street, Tech City, TC 12345 | Phone: (555) 123-4567
        &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="6"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none; font-weight: bold;" colspan="3"&amp;gt;Bill To:&amp;lt;/td&amp;gt;
        &amp;lt;td style="border: none; font-weight: bold; text-align: right;" colspan="3"&amp;gt;Invoice Details:&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="3"&amp;gt;
            John Smith&amp;lt;br&amp;gt;
            ABC Company&amp;lt;br&amp;gt;
            456 Business Ave&amp;lt;br&amp;gt;
            Corporate City, CC 67890
        &amp;lt;/td&amp;gt;
        &amp;lt;td style="border: none; text-align: right;" colspan="3"&amp;gt;
            Invoice #: INV-2024-001&amp;lt;br&amp;gt;
            Date: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;br&amp;gt;
            Due Date: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;br&amp;gt;
            Terms: Net 30
        &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="6"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; text-align: center;"&amp;gt;Item&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; text-align: center;"&amp;gt;Description&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; text-align: center;"&amp;gt;Qty&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; text-align: center;"&amp;gt;Rate&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; text-align: center;"&amp;gt;Amount&amp;lt;/th&amp;gt;
        &amp;lt;th style="background-color: #2E86AB; color: white; text-align: center;"&amp;gt;Tax&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold;"&amp;gt;Web Development&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Custom e-commerce platform with admin dashboard&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center;"&amp;gt;1&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right;"&amp;gt;$15,000&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; font-weight: bold;"&amp;gt;$15,000&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right;"&amp;gt;$1,500&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold;"&amp;gt;UI/UX Design&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;User interface and experience design&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center;"&amp;gt;1&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right;"&amp;gt;$5,000&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; font-weight: bold;"&amp;gt;$5,000&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right;"&amp;gt;$500&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="font-weight: bold;"&amp;gt;Testing&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;Quality assurance and testing services&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: center;"&amp;gt;1&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right;"&amp;gt;$3,000&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right; font-weight: bold;"&amp;gt;$3,000&amp;lt;/td&amp;gt;
        &amp;lt;td style="text-align: right;"&amp;gt;$300&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="6"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="4"&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td style="background-color: #F8F9FA; font-weight: bold; text-align: right;"&amp;gt;Subtotal:&amp;lt;/td&amp;gt;
        &amp;lt;td style="background-color: #F8F9FA; font-weight: bold; text-align: right;"&amp;gt;$23,000&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="4"&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td style="background-color: #F8F9FA; font-weight: bold; text-align: right;"&amp;gt;Tax (10%):&amp;lt;/td&amp;gt;
        &amp;lt;td style="background-color: #F8F9FA; font-weight: bold; text-align: right;"&amp;gt;$2,300&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
        &amp;lt;td style="border: none;" colspan="4"&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td style="background-color: #2E86AB; color: white; font-weight: bold; font-size: 16px; text-align: right;"&amp;gt;TOTAL:&amp;lt;/td&amp;gt;
        &amp;lt;td style="background-color: #2E86AB; color: white; font-weight: bold; font-size: 16px; text-align: right;"&amp;gt;$25,300&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
`&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;invoiceTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./invoice.xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚀 &lt;strong&gt;API Flexibility - Multiple Import Styles&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our package supports multiple import styles for maximum flexibility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Style 1: Default import (class-based)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TableToXlsx&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nodewave/table-to-xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;TableToXlsx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Style 2: Named imports (functional)&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;convertToFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;convertToBuffer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nodewave/table-to-xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;convertToFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./output.xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Style 3: Namespace import&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;TableToXlsx&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nodewave/table-to-xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;TableToXlsx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🎯 &lt;strong&gt;Supported CSS Properties&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our package has the ability to parse and converts these CSS properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Colors&lt;/strong&gt;: &lt;code&gt;background-color&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;border-color&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typography&lt;/strong&gt;: &lt;code&gt;font-size&lt;/code&gt;, &lt;code&gt;font-weight&lt;/code&gt;, &lt;code&gt;text-align&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Borders&lt;/strong&gt;: &lt;code&gt;border&lt;/code&gt;, &lt;code&gt;border-style&lt;/code&gt;, &lt;code&gt;border-color&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Classes&lt;/strong&gt;: &lt;code&gt;text-center&lt;/code&gt;, &lt;code&gt;text-left&lt;/code&gt;, &lt;code&gt;text-right&lt;/code&gt;, &lt;code&gt;font-bold&lt;/code&gt;, &lt;code&gt;font-normal&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚀 &lt;strong&gt;Get Started Today&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @nodewave/table-to-xlsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more painstaking XLSX producer API calls. No more complex cell merging logic. Just write your table in HTML (which you probably already know how to do, or ask AI to do it for you 😜) and let our package handle the rest!&lt;/p&gt;

&lt;h3&gt;
  
  
  🌱  &lt;strong&gt;Contributing to this Package&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;At &lt;a href="https://nodewave.id" rel="noopener noreferrer"&gt;Nodewave&lt;/a&gt;, we believe in collaboration to boost developer productivity and experience. So if you have any idea for this package to extends it functionality any further, please feel free to open an issue and create your PR at our &lt;a href="https://github.com/NodeWave-Engineering/table-to-xlsx" rel="noopener noreferrer"&gt;repository&lt;/a&gt;. And don't forget to drop some ⭐️ to it also 👋.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>backend</category>
    </item>
    <item>
      <title>Dynamic Multi Column and Relational Filtering With Prisma ORM</title>
      <dc:creator>Rizqy Eka Putra</dc:creator>
      <pubDate>Mon, 24 Jul 2023 21:36:03 +0000</pubDate>
      <link>https://dev.to/rizqyep/dynamic-filtering-with-prisma-part-1-3697</link>
      <guid>https://dev.to/rizqyep/dynamic-filtering-with-prisma-part-1-3697</guid>
      <description>&lt;p&gt;If you already use Prisma, then you already know all about the awesomeness, except maybe the migration or schema part when you are working in a big team.&lt;/p&gt;

&lt;p&gt;But anyway, my blog today will be about how we can use Prisma Query to achieve dynamic filtering!&lt;/p&gt;

&lt;p&gt;To give you a little bit more context, what I am talking about is building one function that can apply to all your sql table, with fully customizeable : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aplly Multi-Filtering a table by &lt;code&gt;any column&lt;/code&gt; and &lt;code&gt;it's relation&lt;/code&gt; too!&lt;/li&gt;
&lt;li&gt;Search by &lt;code&gt;any column&lt;/code&gt; and &lt;code&gt;it's relation&lt;/code&gt; too !&lt;/li&gt;
&lt;li&gt;Ordering by any column&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How is this possible?
&lt;/h2&gt;

&lt;p&gt;Maybe some of you guys have already kinda guess it right, it's because, prisma use JS / TS most precious thing (Object) in order to execute any query, especially the &lt;code&gt;findMany&lt;/code&gt; query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
       &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A blog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how the &lt;code&gt;WHERE&lt;/code&gt;clause and &lt;code&gt;ORDER BY&lt;/code&gt; is basically formed by an object? &lt;/p&gt;

&lt;p&gt;That's what we'll experiment with as we go. &lt;br&gt;
In this part 1, we'll go with the &lt;code&gt;WHERE&lt;/code&gt; clause for data filtering first, other things will hopefully covered in next parts of this series ! :D &lt;/p&gt;
&lt;h2&gt;
  
  
  Enough Talk, Lets Get Started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Setting Up
&lt;/h3&gt;

&lt;p&gt;First things first, let's set up our mini server with just some several dependencies &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npm init -y &lt;/p&gt;

&lt;p&gt;npm install express prisma @prisma/client &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't forget to initialize the prisma folders too !&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npx prisma init&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, now we basically have something like this in our project  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;node_modules &lt;/li&gt;
&lt;li&gt;prisma 

&lt;ul&gt;
&lt;li&gt;schema.prisma &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't want to go the hassle of setting-it-up , you can clone the repository &lt;a href="https://github.com/rizqyep/prisma-dynamic-filtering" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Database Config and  Prisma Schema
&lt;/h3&gt;

&lt;p&gt;If you're kinda new, prisma schema also contains the database url, which actually can be overrided later on the code when you initialize prisma client instance.&lt;/p&gt;

&lt;p&gt;All you have to do is just fill in your Database Connection URI in the .env file (generated from &lt;code&gt;npx prisma init&lt;/code&gt;) and choose your provider, i'll be using &lt;code&gt;mysql&lt;/code&gt; for this tutorial. But I think there'll be no difference in postgres too !&lt;/p&gt;

&lt;p&gt;For this tutorial, we'll keep it simple, we'll just do it with two entities &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blogs &lt;/li&gt;
&lt;li&gt;User &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and i'll just use enum for the blog category.&lt;/p&gt;

&lt;p&gt;The schema will look like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

enum BlogCategory {
  BACKEND
  FRONTEND
  MOBILE
}

model Blogs {
  id        String       @id @default(uuid())
  title     String
  content   String
  category  BlogCategory
  writer    User         @relation(fields: [writerId], references: [id])
  writerId  String
  createdAt DateTime     @default(now())
  updatedAt DateTime     @updatedAt
}

model User {
  id       String  @id @default(uuid())
  username String  @unique
  fullName String
  blogs    Blogs[]
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we're done with schema, now we just have to migrate it with this command : &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npx prisma migrate dev --name migrationName&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Folder Structure
&lt;/h3&gt;

&lt;p&gt;Basically, i will just split the code into some parts &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;server.js (Our Express based webserver to do request and response)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;services/blogService.js ( we'll do logics here)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;services/buildFilterQuery.js (we'll apply the filtering before passing it to the query here)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;prisma-instance.js (prisma instance will be stored here)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It'll look basically like this  :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqx20izqmfw4w3dxm5ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqx20izqmfw4w3dxm5ug.png" alt=" " width="183" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Initalizing Server and Prisma Instance
&lt;/h3&gt;

&lt;p&gt;On this part, we'll create one route, and then inside it, we'll check whatever filters that is provided. &lt;/p&gt;

&lt;p&gt;server.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getAll&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./blogs/blogService&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;



&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkFilteringQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// This needs to be parsed into object first, because we are retrieving this from a request query, which is basically just a string.&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderRule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderRule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderRule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/blogs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkFilteringQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[INFO] READY!!!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are a bit confused, i'll explain it shortly, basically in this server.js we already did : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a simple express app&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create one GET routes to retrieve blogs data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And we'll only use combination of filters that client / user choose to pass via request. We are doing this by simply checking it inside the &lt;code&gt;checkFilteringQuery&lt;/code&gt; function and then pass it to the blogService's getAll function (will be explained later).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And next up, it's just a simple task, we'll create a prisma instance in a separate file (just to get close into real-world scenario here :p)&lt;/p&gt;

&lt;p&gt;prisma-instance.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { PrismaClient } = require("@prisma/client")

const prisma = new PrismaClient();


module.exports = {
    prisma
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building The Query and Service
&lt;/h3&gt;

&lt;p&gt;Okay, so now, this is where the magic happens , we'll try to manipulate prisma's findMany query, to be more flexible, matching our end-user requirements of dynamic filtering. &lt;/p&gt;

&lt;p&gt;services/buildQuery.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildFilterQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usedFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;


    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="cm"&gt;/*
                Filters would look like this : 

                {
                    "filter1":["a","b"],
                    "filter2":["a"]
                }
            */&lt;/span&gt;


        &lt;span class="c1"&gt;// First, we'll loop through the key inside enabledFilters . filters&lt;/span&gt;

        &lt;span class="c1"&gt;// IT'S IMPORTANT THAT key of these filter object, reflect to the column in our database !&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="c1"&gt;// We'll store the filter values (array of value that we want to be inside where clause, to make the code more readable)&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filterValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;



            &lt;span class="cm"&gt;/* In this part we'll include relational filter as well, such as user.fullName or user.username
                It's because, prisma support this, the where clause will looks like : 

                where:{
                    relation:{
                        column : "value"
                    }
                }

            */&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="cm"&gt;/*If values array length is just 1 , we'll just filter for exact match 

                 Pretty much like : 

                    prisma.blog.findMany({
                        where:{
                            relation:{
                                column: "value"
                            }
                        }
                    })

                */&lt;/span&gt;

                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filterValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="cm"&gt;/*But if values array length is more than 1 , we'll filter with `in` operator

                 Pretty much like : 

                    prisma.blog.findMany({
                        where:{
                            relation:{
                                column: {
                                    in : ["value1", "value2"]
                                }
                            }
                        }
                    })

                */&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filterValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="cm"&gt;/* This next part, is for filtering column that is available in our table 

                where:{
                    column:"value"
                }

            */&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filterValues&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="p"&gt;})&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filterValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="p"&gt;});&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;



    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/*
            Same logic as filter applied here, if the searchKey include ".", then it means we are searching based on relation
        */&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;enabledFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;



    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right now, the code may looks a bit crazy, but for now let's just try to understand the code based on comments that I already put there, and later on, during the testing part, I'll break it down about how the filter is applied in various cases. &lt;/p&gt;

&lt;p&gt;Now we're done building the query, we'll call prisma's find many and from our blogService , &lt;/p&gt;

&lt;p&gt;services/blogService.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../prisma-instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildFilterQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./buildQuery&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getAll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usedFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildFilterQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;usedFilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;blogs&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;getAll&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tests and Explanation
&lt;/h2&gt;

&lt;p&gt;Okay, i've promised you that the crazy looking code from some minutes ago, is going to be explained here as we test the functionality right &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Data shown below is inserted by seeding, you can find it on repository I have listed for you back on setup section !&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Test 1 : Filter by Blog's Category
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Filtering by One Category &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t4baxizljiqtzdia91n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5t4baxizljiqtzdia91n.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, so what is happening here is: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We provide a request query of : &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;{"category":["BACKEND"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;which our &lt;code&gt;buildFilterQuery&lt;/code&gt; function translates into :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="nl"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;combine this with the full prisma query in &lt;code&gt;blogService.js&lt;/code&gt;, it will actually looks like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="na"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
     &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we want to filter blog with category of &lt;code&gt;BACKEND&lt;/code&gt; and &lt;code&gt;FRONTEND&lt;/code&gt;? &lt;/p&gt;

&lt;p&gt;Easy! we'll just pass this into the request query : &lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"category":["BACKEND","FRONTEND"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and it'll translate to this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="nl"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FRONTEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;combine this with the full prisma query in &lt;code&gt;blogService.js&lt;/code&gt;, it will actually looks like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="na"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FRONTEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
     &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that if we give multiple argument to it, it will need to use the 'in' operator. &lt;/p&gt;

&lt;h4&gt;
  
  
  Test 2 : Filtering by Category + Searching
&lt;/h4&gt;

&lt;p&gt;The Request Will Look Like this : &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6rxjo2imm06tmb6xnsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc6rxjo2imm06tmb6xnsy.png" alt=" " width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then, our &lt;code&gt;buildFilterQuery&lt;/code&gt; function, will simply translate this into :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="nl"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
           &lt;span class="na"&gt;contains&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Part 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the full query will be :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
     &lt;span class="na"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
           &lt;span class="na"&gt;contains&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Part 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
     &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Test 3 (Bonus) Filter by Category and Search By Writer's Name
&lt;/h4&gt;

&lt;p&gt;Oh yes, we can do that ! &lt;br&gt;
If you look at filter query, for filtering and searching, we have if condition that will check if the filter key or the &lt;code&gt;searchKey&lt;/code&gt; contains "." inside of it, &lt;/p&gt;

&lt;p&gt;to use it we'll just simply do : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fercm77ksifwtjgq7hogy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fercm77ksifwtjgq7hogy.png" alt=" " width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and our &lt;code&gt;buildFilterQuery&lt;/code&gt; translate this into :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="nl"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
           &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
              &lt;span class="na"&gt;contains&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Writer 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the full query will be :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;blogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="na"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BACKEND&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
           &lt;span class="na"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
              &lt;span class="na"&gt;contains&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Writer 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
     &lt;span class="na"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So at last, we got an Object Relation Mapper that works really-well with Object Manipulaton Right ! &lt;/p&gt;

&lt;p&gt;With this, you can even have many more endpoints and will just have to apply this one filtering function for all different entities in your application. &lt;/p&gt;

&lt;p&gt;Stay tuned for the next parts where we will go through more with things like ordering, paginating (with cursor and limit-offset). &lt;/p&gt;

&lt;p&gt;Cheers ! &lt;/p&gt;

&lt;p&gt;Github Repository: &lt;a href="https://github.com/rizqyep/prisma-dynamic-filtering" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connect With Me : &lt;br&gt;
&lt;a href="https://linkedin.com/in/rizqyep" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>backend</category>
    </item>
    <item>
      <title>Simple CRUD REST API With Lumen + MySQL + Eloquent ORM</title>
      <dc:creator>Rizqy Eka Putra</dc:creator>
      <pubDate>Wed, 21 Oct 2020 18:12:41 +0000</pubDate>
      <link>https://dev.to/rizqyep/simple-crud-rest-api-with-lumen-mysql-eloquent-orm-dkf</link>
      <guid>https://dev.to/rizqyep/simple-crud-rest-api-with-lumen-mysql-eloquent-orm-dkf</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Hello there ! I am Rep , Software Engineer in the making and currently a 3rd year Computer Engineering student ! In this post i am going to share a quick guide on creating a CRUD ( Create , Read , Update , Delete ) Rest API With Lumen , MySQL Database and also Eloquent ORM .&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Why Lumen ?&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;When you are only intended to Create an API , you wont need lots of Laravel default Libraries / Dependencies , because the goals is only to output a plain data formatted with most probably JSON , therefore we'll use Lumen , a micro-framework which utilize laravel's best part , with smaller size and faster execution time too!&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;What should i know or have to follow this post?&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Make sure you already installed :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;PHP 7.2 or Higher&lt;/li&gt;
&lt;li&gt;Composer &lt;/li&gt;
&lt;li&gt;MySQL Server ( You can install it via XAMPP on Windows , or via your favorite Packet Manager on UN*X like system)&lt;/li&gt;
&lt;li&gt;PHPMyAdmin ( You get this automatically via XAMPP , you can install it on linux via Packet Manager also)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Knowledge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Several things you need to know before following this post :
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Basic Request / Response on Web &lt;/li&gt;
&lt;li&gt;PHP ( Very , very , very mandatory )&lt;/li&gt;
&lt;li&gt;A bit of Laravel Knowledge&lt;/li&gt;
&lt;li&gt;SQL Knowledge (would be really helpful)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Configuring the Project&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;In this tutorial , we'll create a simple CRUD for a Product Entity , we'll name our project "product-rest-api" , please kindly remember that by the time this tutorial is being written , the latest release of Lumen and Laravel is 8.0 .&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating The Project
&lt;/h3&gt;

&lt;p&gt;Firstly , we'll have to create the project first , by executing this command :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foasduyegejtmq9ptm3bv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foasduyegejtmq9ptm3bv.png" alt="Alt Text" width="800" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the project has successfuly built , you can change your directory to the project directory (product-rest-api) and run this command to start the server : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqti8097hsb3p8k5ghagx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqti8097hsb3p8k5ghagx.png" alt="Alt Text" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can test the endpoint via Postman or Your web browser by sending a GET request to the "/" route &lt;/p&gt;

&lt;p&gt;Result : &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fum5fvk9rhd265r5wp30v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fum5fvk9rhd265r5wp30v.png" alt="Alt Text" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you get the same response as shown on image above , it means that the project has built sucessfully and you're ready to move on to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring The Database
&lt;/h3&gt;

&lt;p&gt;We need a database to later save / hold the migrated table from lumen , therefore we'll need to create one in MySQL , i'll give the database name "product-rest" , and i'll do it via the terminal to speed up the process , you can also create it via PHPMyAdmin.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Note : if you are using Windows and XAMPP , dont forget to turn on the MySQL Service and Apache (if you are going to use PHPMyAdmin) via the XAMPP Control Panel.&lt;br&gt;
If you are using linux , start the mysql / mariadb service via your terminal&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating The Database Via Terminal / CMD :
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkdmh5guw9pivpwf3el0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkdmh5guw9pivpwf3el0m.png" alt="Alt Text" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you're done with the database , now open your favorite Code Editor and open your project folder . Once your project folder are loaded , open the &lt;code&gt;.env&lt;/code&gt; file , and do the configuration for your project database &lt;strong&gt;(don't forget to stop the server running first)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffp8cnaxxjxostuflh5nn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffp8cnaxxjxostuflh5nn.png" alt="Alt Text" width="722" height="1092"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Important part of the &lt;code&gt;.env&lt;/code&gt; file configuration as shown above is to make sure you filled your Database Configuration correctly , configuration related to Database are those started with &lt;code&gt;**DB_**&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One more step is done , the next step is to create the database migration or defining the database schema , while working with laravel , you could easily utilize the artisan's &lt;code&gt;make:model&lt;/code&gt; with -m option to automatically generate a model and a migration , unfortunately this is not available in Lumen , therefore we'd have to create the migration first and later on , create the Model .&lt;/p&gt;

&lt;p&gt;Create the product table migration with this command  :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9whr6n37p5un6mlpclke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9whr6n37p5un6mlpclke.png" alt="Alt Text" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Command above will create you a migration file which will be located on &lt;code&gt;database/migrations&lt;/code&gt; , locate the &lt;code&gt;create_products_table&lt;/code&gt; file and open it up.&lt;/p&gt;

&lt;p&gt;Once you already opened it , we'll start on Creating the product schema , it'll just have some basics data like :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name&lt;/li&gt;
&lt;li&gt;Price&lt;/li&gt;
&lt;li&gt;Category&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets jump right into the code , inside the &lt;code&gt;CreateProductsTable&lt;/code&gt; class , you will find a &lt;code&gt;public function up()&lt;/code&gt; , we'll define our schema there , or to put simply , the function will looked like this : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv7m1rb1ysmz7wunr3rdy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv7m1rb1ysmz7wunr3rdy.png" alt="Alt Text" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we already done with defining the schema , we would have to create a Model class named &lt;code&gt;Product.php&lt;/code&gt; , but before we do that , keep in mind that Lumen dont have Facades nor Eloquent enabled by default , therefore we'll need to first turn it on by uncommenting these following lines located on &lt;code&gt;bootstrap/app.php&lt;/code&gt; on line 26 and 28 respectively&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line to Uncomment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$app-&amp;gt;withFacades();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$app-&amp;gt;withEloquent();&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next thing is to create the Product.php file inside the app/Models directory , and fill it with these code : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdzzlww8vc3rn0chkuqgu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdzzlww8vc3rn0chkuqgu.png" alt="Alt Text" width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;protected $guarded = []&lt;/code&gt; means that we'll allow the web app to fill datas to any column on the table.&lt;/p&gt;

&lt;p&gt;The last configuration we'll have to do is to run the migration , it can be done by simply running this command below &lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check your database , and see you'll get the product table with 4 columns containing id , name , price and category .&lt;/p&gt;

&lt;h1&gt;
  
  
  Building The Logic
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Defining the routes
&lt;/h3&gt;

&lt;p&gt;Our API will have 5 Endpoints , those are : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /product to get all products data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /product/{id} to get a product by its ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST /product to create new product&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT /product/{id} to update a product base on its id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /product/{id} to delete a product base on its id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we create the routes , it'll be better to create the controller first and then create functions that will represents each action. In order to do so , we need to create a &lt;code&gt;ProductController.php&lt;/code&gt; file first on the app/Http/Controllers directory &lt;/p&gt;

&lt;p&gt;First , we'll need to use the Product Model inside this class and we'll also need to parse incoming request , therefore we'll add these lines of code: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;use App\Models\Product;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;use Illuminate\Http\Request;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And after that , we'll need to create a function that would return all Products data , to do so , we'll create a function named index , the controller will look pretty much like this : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsaz7bngrqufladwmjpzv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsaz7bngrqufladwmjpzv.png" alt="Alt Text" width="800" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next up, below the index function , we'll create a function called show , which will take up a parameter of id , and return a product based on it id :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3e5d1ba5drpjnl6r6j4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3e5d1ba5drpjnl6r6j4j.png" alt="Alt Text" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're done showing products , now its time to create a new one with the create function , which will accept a parameter of &lt;code&gt;$request with type Request&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flfgnd15gushmyqvqmq9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flfgnd15gushmyqvqmq9n.png" alt="Alt Text" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fancy an update to your product? we'll create  a function which will takes two parameter consist of &lt;code&gt;$request with type Request&lt;/code&gt; and the product's id we're going to update : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fova5j44itw9pu9hau16k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fova5j44itw9pu9hau16k.png" alt="Alt Text" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What will happen if the product is no longer produced ? it will get deleted from the product list , therefore the last function we are going to create is a delete function which will takes up a parameter of product id : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fap1o6a9lpo1zaas9n7ni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fap1o6a9lpo1zaas9n7ni.png" alt="Alt Text" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Full ProductController.php Code would look like this : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm5gm69ss3usnrf6iorzv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm5gm69ss3usnrf6iorzv.png" alt="Alt Text" width="800" height="1347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating The Routes
&lt;/h2&gt;

&lt;p&gt;We're done with all the logics , but how could we access all these logics , the answer is by binding the route to the controller's function .&lt;/p&gt;

&lt;p&gt;Navigate to routes directory , and open up the web.php , we'll changed it , so it'll match the routes we have defined above before :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foxcf3d5y2fapnxbw56q1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foxcf3d5y2fapnxbw56q1.png" alt="Alt Text" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it for the codes and logic stuff , next up we'll test the Routes , starting from creating the product first , you might realize that we dont have any product yet .&lt;/p&gt;

&lt;p&gt;** Note : you could also use Seeder to Seed data into your database first **&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing the EndPoints
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Create Product
&lt;/h3&gt;

&lt;p&gt;Create a POST request to &lt;code&gt;localhost:8000/product&lt;/code&gt; via Postman , and fill the body section with raw option , and toggle the JSON Option , more or less like this : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flk0z7rece1jj8odvt7mn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flk0z7rece1jj8odvt7mn.png" alt="Alt Text" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create 2 or 3 Products so that we could see the difference between index and show function afterwards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show Products
&lt;/h3&gt;

&lt;p&gt;Now open a new tab in postman, we'll send a GET request to &lt;code&gt;localhost:8000/product&lt;/code&gt; which is binded to &lt;code&gt;index()&lt;/code&gt; function and will return all products &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fau0e3gpq1nwf0dt0yw28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fau0e3gpq1nwf0dt0yw28.png" alt="Alt Text" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And turns out , it works , it gives us all of the products data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show Product by ID
&lt;/h3&gt;

&lt;p&gt;In my products data , i have products with ID of 2 , 3 and 4 , you could check it from the previous response , and try to access only 1 product by sending a GET Request to &lt;code&gt;localhost:8000/{id}&lt;/code&gt; in this case i'll try to get a product with id of 2 , so the request will be a GET to &lt;code&gt;localhost:8000/2&lt;/code&gt; : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdxcxwjdzj6kgsmq8mqex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdxcxwjdzj6kgsmq8mqex.png" alt="Alt Text" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes ! it responded correctly by showing us only a data which id is 2 .&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Product
&lt;/h3&gt;

&lt;p&gt;To update a product , we'll have to send a PUT request, which will require request parameters , just like we did with &lt;strong&gt;Create Product&lt;/strong&gt; request , and the id of product we're going to update , therefore it will be a PUT request to : &lt;code&gt;localhost:8080/product/{id}&lt;/code&gt; this time i will update the previous data of ID 2 , and change the product price to $3000 , notice that you'll need to re-write the name and category data as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faj76ymf6f1ju2bzc54rp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faj76ymf6f1ju2bzc54rp.png" alt="Alt Text" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And once again , it works perfectly , it send us back a json response with the product's updated data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete a Product
&lt;/h2&gt;

&lt;p&gt;Because i changed the price just recently , turns out people are started to grab the Laptops very quickly and it is now out of stock until a new version released .&lt;/p&gt;

&lt;p&gt;So now we'd have to delete the product , by sending a DELETE request to &lt;code&gt;localhost:8000/product/2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We'll also later validate this request by showing all products, because it should have been gone afterwards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqpzdyhpkl0hc3a1si7pn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqpzdyhpkl0hc3a1si7pn.png" alt="Alt Text" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if we checked it by sending a GET request to &lt;code&gt;/product&lt;/code&gt; , it returned : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgw66kb3b1peqp4r1zp3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgw66kb3b1peqp4r1zp3y.png" alt="Alt Text" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has been verified that all of the routes are working properly , because it only responded with 2 items with ID of 3 and 4.&lt;/p&gt;

&lt;h1&gt;
  
  
  That's a Wrap
&lt;/h1&gt;

&lt;p&gt;Thanks for you all who finally made it to the bottom and successfully created a REST API with Lumen , there's a lot of things you could improve from the current API , such as request validation etc. &lt;/p&gt;

&lt;p&gt;And if you want to see the source code , feel free to fork it from my repository at : &lt;a href="https://github.com/rizqyep/product-rest-api" rel="noopener noreferrer"&gt;https://github.com/rizqyep/product-rest-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy Coding !&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>sql</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
