<?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: Bruno Mendola</title>
    <description>The latest articles on DEV Community by Bruno Mendola (@brunomendola).</description>
    <link>https://dev.to/brunomendola</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F26031%2F82664084-06cd-49ce-8f54-4a8e3dfea849.jpg</url>
      <title>DEV Community: Bruno Mendola</title>
      <link>https://dev.to/brunomendola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brunomendola"/>
    <language>en</language>
    <item>
      <title>Build Like a Pro, Spend Like a Student</title>
      <dc:creator>Bruno Mendola</dc:creator>
      <pubDate>Thu, 29 May 2025 10:14:50 +0000</pubDate>
      <link>https://dev.to/brunomendola/build-like-a-pro-spend-like-a-student-144k</link>
      <guid>https://dev.to/brunomendola/build-like-a-pro-spend-like-a-student-144k</guid>
      <description>&lt;h3&gt;
  
  
  Coding Like a Boss on a Zero-Dollar Budget (Open Source Dev Edition)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Build Like a Pro, Spend Like a Student &lt;/strong&gt; — How I’m using world-class dev tools — for free — to power open-source projects that shine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ever felt like building something awesome, but your wallet stared back at you like “lol nope”?&lt;/p&gt;

&lt;p&gt;Yeah, same here.&lt;/p&gt;

&lt;p&gt;Open-source devs live in a strange paradox: we’re building software that &lt;em&gt;literally&lt;/em&gt; powers the world, but most of us are doing it in our spare time, without any budget, often with laptops held together by duct tape and sheer willpower.&lt;/p&gt;

&lt;p&gt;So how do you give your open-source project that enterprise-grade glow without spending a dime?&lt;/p&gt;

&lt;p&gt;Well, it turns out we’re living in a golden age of free tools — &lt;em&gt;good ones&lt;/em&gt;, not janky trialware or open-core “gotchas.” Here’s what I use, and how it helps me build projects like &lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;Querity&lt;/a&gt; without burning a cent.&lt;/p&gt;

&lt;h3&gt;
  
  
  🐙 GitHub: Where It All Begins
&lt;/h3&gt;

&lt;p&gt;GitHub is way more than just a place to version source code and forget it exists. If you dig in, it gives you tooling that some companies charge serious money for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Branch protection rules&lt;/strong&gt; : Enforce code reviews and CI checks before merging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in issue tracking&lt;/strong&gt; : It’s not Jira, and that’s exactly why we love it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actions&lt;/strong&gt; : Want CI/CD pipelines that just &lt;em&gt;work&lt;/em&gt;? GitHub Actions will run your tests, build your docs, deploy your site — all with a few YAML lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependabot&lt;/strong&gt; : Opens PRs to keep your deps updated and your project secure — it’s like a clingy intern, but actually useful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security scanning&lt;/strong&gt; : Quietly catches vulnerabilities so your project doesn’t make the news for the wrong reasons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Pages&lt;/strong&gt; : Want a slick site for your docs or landing page? Click, click, boom — your project has a web presence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the above is &lt;strong&gt;free of charge&lt;/strong&gt; for open-source projects!&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 SonarCloud: Your Judgy Best Friend
&lt;/h3&gt;

&lt;p&gt;This one is for the devs who like their code with a side of guilt.&lt;/p&gt;

&lt;p&gt;SonarCloud is like having that one teammate who catches &lt;em&gt;everything&lt;/em&gt; — duplicate code, complexity, missing coverage — and won’t let you merge anything that smells off.&lt;/p&gt;

&lt;p&gt;Best part? It’s &lt;strong&gt;free for public repos&lt;/strong&gt; and integrates beautifully with GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻 JetBrains IDEs: Writing Code Like a Rockstar
&lt;/h3&gt;

&lt;p&gt;JetBrains doesn’t just make good IDEs — they make IDEs that &lt;em&gt;feel&lt;/em&gt; like magic.&lt;/p&gt;

&lt;p&gt;If you’ve ever used IntelliJ IDEA, WebStorm, or PyCharm, you know what I mean. And guess what? If you’re working on a non-commercial open-source project, &lt;strong&gt;you can get a free license&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You’ll get smart refactors, insane autocomplete, and a UX that makes you forget Eclipse ever existed.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Publishing Like a Pro (for Free)
&lt;/h3&gt;

&lt;p&gt;After your code passes every check and review, it’s time to ship it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maven Central&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;npmjs&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both let you publish open-source packages for free, assuming you follow their rules — mostly around proper metadata, signing, and licensing. Nothing too scary.&lt;/p&gt;

&lt;p&gt;Once you’re in, people can pull your package into projects worldwide with a single line in their pom.xml or package.json.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ A Day in the Life of a Modern OSS Dev
&lt;/h3&gt;

&lt;p&gt;Let’s say you’re working on a library. Here’s how a typical workflow might look:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push code to GitHub&lt;/li&gt;
&lt;li&gt;GitHub Actions run your tests and linters&lt;/li&gt;
&lt;li&gt;SonarCloud checks for bugs, smells, and missing tests&lt;/li&gt;
&lt;li&gt;Dependabot nags you about old dependencies&lt;/li&gt;
&lt;li&gt;You fix everything inside IntelliJ like a wizard&lt;/li&gt;
&lt;li&gt;You publish to Maven Central or npmjs&lt;/li&gt;
&lt;li&gt;Docs are auto-updated and deployed with GitHub Pages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;All this — for $0.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seriously. You don’t need a VC-backed dev environment to build amazing software anymore. Just a bit of setup, and you’re rolling with a dream team of free tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎉 Case Study: Querity
&lt;/h3&gt;

&lt;p&gt;I got to experience all this firsthand with &lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;Querity&lt;/a&gt; — an open-source Java library I built to simplify querying databases (SQL &lt;em&gt;and&lt;/em&gt; NoSQL) from REST APIs.&lt;/p&gt;

&lt;p&gt;It takes care of filtering, sorting, and pagination — and it powers a React-based query builder UI too. If you’re a Java dev working with REST and databases, check it out!&lt;/p&gt;

&lt;p&gt;And if it makes your life easier? &lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;Toss a ⭐️ my way&lt;/a&gt;. It helps.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Open source is more than code. It’s a mindset — building things that matter and sharing them with the world.&lt;/p&gt;

&lt;p&gt;Thanks to these powerful, free tools, you don’t need a massive budget to do that anymore. Just curiosity, caffeine, and a bit of consistency.&lt;/p&gt;

&lt;p&gt;If you’re thinking about starting your own OSS project, this is the best time in history to do it.&lt;/p&gt;

&lt;p&gt;Go build something great.&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%2Ftgbu3iy6vaq4biy84uwg.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%2Ftgbu3iy6vaq4biy84uwg.png" alt="To succeed, you must share." width="520" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>tools</category>
      <category>softwareengineering</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Stop Hammering Screws: Tech Choices That Make Sense</title>
      <dc:creator>Bruno Mendola</dc:creator>
      <pubDate>Tue, 29 Apr 2025 14:52:08 +0000</pubDate>
      <link>https://dev.to/brunomendola/stop-hammering-screws-tech-choices-that-make-sense-1dp0</link>
      <guid>https://dev.to/brunomendola/stop-hammering-screws-tech-choices-that-make-sense-1dp0</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AbPxBKV38Cm2fgth2" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AbPxBKV38Cm2fgth2" width="760" height="760"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“If the only tool you have is a hammer, every problem looks like a nail.”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
 — Probably every senior dev after debugging a junior’s code&lt;/p&gt;

&lt;p&gt;In the software world, I constantly see teams reach for their favorite stack — regardless of whether it’s the right fit for the job. A new module? Same stack. A quick tool for internal use? Same stack. A real-time data pipeline? Yep… same stack.&lt;/p&gt;

&lt;p&gt;The result? Overengineered solutions, underwhelming performance, and developers silently sobbing into their keyboards.&lt;/p&gt;

&lt;p&gt;And I get it. Even I — someone who’s worked with BASIC, Pascal, shell scripting, C, Delphi, PHP, Java, Spring, .NET, Angular, React — have made that mistake. It’s easy to fall in love with the tool you know best. But the longer I’ve worked in software (especially building ERP systems for demanding industries), the more I’ve learned a hard truth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;No tool is good for everything. Every tech decision is a trade-off.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s dig into that.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Happens When the Tool Dictates the Architecture
&lt;/h3&gt;

&lt;p&gt;You know this scenario:&lt;br&gt;&lt;br&gt;
A team is asked to build a small reporting dashboard.&lt;br&gt;&lt;br&gt;
They reach for their usual weapons: Spring Boot, full REST API, PostgreSQL, React frontend, maybe even Docker and a CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;Was the problem complex? Not really.&lt;br&gt;&lt;br&gt;
Did it need all this? Definitely not.&lt;/p&gt;

&lt;p&gt;But that’s what they know. So now you’ve got a monstrous mini-project with 12 moving parts, when a single-page app with a SQLite file might have done the job in half a day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meme Intermission 🧠
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Junior Dev:&lt;/strong&gt; “We need to build a blog.”&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Senior Dev:&lt;/strong&gt; “Just use WordPress.”&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Junior Dev after 6 months of building their own CMS from scratch in Rust with a GraphQL backend, React frontend, and blockchain integration:&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%2Fuploads%2Farticles%2F4i36iyxll9uwman4lghl.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%2F4i36iyxll9uwman4lghl.png" width="610" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Start From Requirements, Not Comfort Zones
&lt;/h3&gt;

&lt;p&gt;If you build enterprise systems like I do, you’ve probably noticed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some parts of your system need rock-solid consistency → &lt;strong&gt;relational DBs&lt;/strong&gt; make sense.&lt;/li&gt;
&lt;li&gt;Some areas need blazing-fast search over massive documents → &lt;strong&gt;Elastic or vector DBs&lt;/strong&gt; might be right.&lt;/li&gt;
&lt;li&gt;For highly dynamic UI interactions? &lt;strong&gt;React&lt;/strong&gt; or similar makes a difference.&lt;/li&gt;
&lt;li&gt;For quick internal tools? Even &lt;strong&gt;low-code&lt;/strong&gt; might work better than a full-stack solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But I still see devs trying to solve &lt;strong&gt;everything&lt;/strong&gt; with Spring Boot + PostgreSQL + Angular. Or Node.js + MongoDB + React. Or even .NET for things that don’t even touch Windows.&lt;/p&gt;

&lt;p&gt;Why? Familiarity. Comfort. Fear of risk.&lt;/p&gt;

&lt;p&gt;The irony? &lt;strong&gt;Choosing the wrong tool out of comfort is a bigger risk than learning something better suited.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It’s All Trade-offs
&lt;/h3&gt;

&lt;p&gt;There’s no magic bullet. Everything has pros and cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; gives you flexibility — and 10,000 decisions to make before writing a button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring&lt;/strong&gt; is powerful — and occasionally eats your weekend debugging autoconfiguration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt; is fast and flexible — until you realize you needed transactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; is reliable — until you’re denormalizing like crazy just for performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve been around enough stacks (and I’ve seen quite a few), you stop asking &lt;em&gt;“What’s the best?”&lt;/em&gt; and start asking &lt;em&gt;“What fits this problem?”&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Meme Intermission #2 📈
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Dev 1:&lt;/strong&gt; “Why did you rewrite the app in Go?”&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Dev 2:&lt;/strong&gt; “Because Go is fast and can scale to billion users.”&lt;br&gt;&lt;br&gt;
&lt;strong&gt;App:&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%2Fuploads%2Farticles%2Fq63tsq356rj8qp3e2dtz.gif" 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%2Fq63tsq356rj8qp3e2dtz.gif" width="220" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A Better Way to Think
&lt;/h3&gt;

&lt;p&gt;Here’s how I encourage my team (and remind myself) to evaluate tech choices:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ 1. What are the real needs?
&lt;/h3&gt;

&lt;p&gt;Is the data relational? Will it scale? Does it need to be real-time? How often will it change?&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ 2. Who will maintain it?
&lt;/h3&gt;

&lt;p&gt;The best tech in the world is useless if the team hates working with it — or worse, doesn’t understand it.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ 3. Is this solving the problem or just showing off?
&lt;/h3&gt;

&lt;p&gt;If the tech stack is starting to look like a spaceship for a paper plane problem, step back.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ 4. Can we evolve this later?
&lt;/h3&gt;

&lt;p&gt;Start simple. Prove the value. Then scale. A good MVP is often a smart script or monolith, not a distributed system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing Thoughts
&lt;/h3&gt;

&lt;p&gt;If you take anything from this article, let it be this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Each job its tool. Each tool its trade-off.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don’t chase trends. Don’t cling to what you know just because you know it. You don’t need to know &lt;em&gt;everything&lt;/em&gt;, but you &lt;em&gt;do&lt;/em&gt; need the wisdom to know when to look beyond your comfort zone.&lt;/p&gt;

&lt;p&gt;The best developers I’ve worked with aren’t the ones who know 10 languages — they’re the ones who know &lt;em&gt;how to choose&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;🧰 Be a software carpenter. Pick the right tool.&lt;br&gt;&lt;br&gt;
🎯 Aim for solutions, not stacks.&lt;br&gt;&lt;br&gt;
💪 Don’t fear the change when you can lead the change.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Introducing Querity React Components: Streamline Your Frontend Query Interfaces</title>
      <dc:creator>Bruno Mendola</dc:creator>
      <pubDate>Wed, 09 Apr 2025 07:16:16 +0000</pubDate>
      <link>https://dev.to/brunomendola/introducing-querity-react-components-streamline-your-frontend-query-interfaces-2bj7</link>
      <guid>https://dev.to/brunomendola/introducing-querity-react-components-streamline-your-frontend-query-interfaces-2bj7</guid>
      <description>&lt;p&gt;In a &lt;a href="https://dev.to/brunomendola/easily-query-sql-and-nosql-databases-in-your-java-application-with-one-single-language-3ile-temp-slug-6999644"&gt;previous article&lt;/a&gt; I introduced &lt;a href="https://queritylib.github.io/querity" rel="noopener noreferrer"&gt;Querity&lt;/a&gt;, a Java library designed to simplify querying both SQL and NoSQL databases using a unified language. Querity makes exposing data through REST APIs effortless.&lt;/p&gt;

&lt;p&gt;Building upon that foundation, I’m excited to announce &lt;strong&gt;Querity React Components&lt;/strong&gt; , a set of React components that bring the same ease of use to your frontend applications.&lt;/p&gt;

&lt;p&gt;Available on npm:&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@queritylib/react" rel="noopener noreferrer"&gt;@queritylib/react&lt;/a&gt;&lt;br&gt;&lt;br&gt;
and of course GitHub:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/queritylib/querity-react" rel="noopener noreferrer"&gt;https://github.com/queritylib/querity-react&lt;/a&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%2Fuploads%2Farticles%2Fc2yqh27q4l28ho2q92ys.jpeg" 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%2Fc2yqh27q4l28ho2q92ys.jpeg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Querity React Components?
&lt;/h3&gt;

&lt;p&gt;Integrating query capabilities into frontend applications can be challenging: queries for real world use-cases can get complex, and creating an interface to support that kind of complexity can take some effort.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Querity React Components&lt;/strong&gt; , you can easily create user interfaces that allow users to construct and execute queries, seamlessly interacting with your Querity-powered backend.&lt;/p&gt;
&lt;h4&gt;
  
  
  Key Components
&lt;/h4&gt;

&lt;p&gt;The library offers two primary components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;QuerityField&lt;/strong&gt; : A text input component for entering and validating queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QuerityBuilderUI&lt;/strong&gt; : A visual interface for visually building complex queries without manual input.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;To get started, install the package using npm or yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @queritylib/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @queritylib/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Wrap your application with the QuerityComponentsProvider to provide necessary components and styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {useState} from 'react';
import {
  QuerityComponentsProvider,
  defaultQuerityComponents,
  QuerityField,
  QuerityBuilderUI
} from '@queritylib/react';
import '@queritylib/react/themes/default/style.css';

function App() {
  return (
    &amp;lt;QuerityComponentsProvider value={defaultQuerityComponents}&amp;gt;
      &amp;lt;QueryInterface /&amp;gt;
    &amp;lt;/QuerityComponentsProvider&amp;gt;
  );
}

function QueryInterface() {
  const [query, setQuery] = useState('');
  const [data, setData] = useState([]);

  const fetchData = async (query: string) =&amp;gt; {
    const response = await fetch(`/api/data?q=${query}`);
    // error handling omitted
    const responseData = await response.json();
    setData(responseData.items);
  }

  return (
    &amp;lt;&amp;gt;
      &amp;lt;QuerityField
        value={query}
        placeholder="Enter your query"
        onChange={(q) =&amp;gt; setQuery(q)}
        onEnter={() =&amp;gt; fetchData(query)}
        onInvalidQuery={(error) =&amp;gt; console.error('Invalid query:', error)}
      /&amp;gt;
      &amp;lt;QuerityBuilderUI
        query={query}
        onChange={(q) =&amp;gt; setQuery(q)}
      /&amp;gt;
      &amp;lt;table&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;th&amp;gt;ID&amp;lt;/td&amp;gt;
          &amp;lt;!-- other headers omitted --&amp;gt;
        &amp;lt;/tr&amp;gt;
        {data.map((item) =&amp;gt; (
          &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;${item.id}&amp;lt;/td&amp;gt;
            &amp;lt;!-- other columns omitted --&amp;gt;
          &amp;lt;/tr&amp;gt;
        ))}
      &amp;lt;/table&amp;gt;
    &amp;lt;/&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QuerityField&lt;/strong&gt; provides a text input for users to enter queries, with handlers for change events, submissions, and validation errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QuerityBuilderUI&lt;/strong&gt; offers a visual interface for constructing queries, with the possibility of infinitely nesting the conditions and a handler for query changes.&lt;/p&gt;

&lt;p&gt;As you can see, the two components can communicate with each other via a shared state, so the changes to one are reflected on the other.&lt;/p&gt;

&lt;p&gt;The optional import of the &lt;strong&gt;default theme&lt;/strong&gt; (@queritylib/react/themes/default/style.css) gives a nice look-and-feel to the components. Alternatively, you can create a custom stylesheet and avoid this import (see next section).&lt;/p&gt;

&lt;p&gt;Here’s how QuerityBuilderUI looks with the &lt;strong&gt;default theme&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%2Fuploads%2Farticles%2F2s5p6j1pr1kowcnfqsiy.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%2F2s5p6j1pr1kowcnfqsiy.png" width="773" height="826"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Querity React Components styled with default theme&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;Querity React Components are designed to be flexible and can be customized to fit your application's styling needs. By overriding the default components provided to the QuerityComponentsProvider, you can integrate with various CSS frameworks like &lt;strong&gt;Tailwind CSS&lt;/strong&gt; , &lt;strong&gt;MUI&lt;/strong&gt; , or &lt;strong&gt;Bootstrap&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, to customize components with Tailwind CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  QuerityComponentsProvider,
  defaultQuerityComponents,
  QuerityField,
  QuerityBuilderUI
} from '@queritylib/react';

const customComponents = {
  ...defaultQuerityComponents,
  Input: (props) =&amp;gt; &amp;lt;input {...props} className={`${props.className} border p-2`} /&amp;gt;,
  Select: (props) =&amp;gt; &amp;lt;select {...props} className={`${props.className} border p-2`} /&amp;gt;,
  Button: (props) =&amp;gt; &amp;lt;button {...props} className={`${props.className} bg-gray-200 p-2 cursor-pointer mr-1`} /&amp;gt;,
  Checkbox: (props) =&amp;gt; (
      &amp;lt;label className="inline-flex items-center cursor-pointer"&amp;gt;
        &amp;lt;input type="checkbox" {...props} className="sr-only peer"/&amp;gt;
        &amp;lt;div 
            className="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;span className="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300"&amp;gt;{props.label}&amp;lt;/span&amp;gt;
      &amp;lt;/label&amp;gt;
  )
};

function App() {
  return (
    &amp;lt;QuerityComponentsProvider value={customComponents}&amp;gt;
      &amp;lt;QueryInterface /&amp;gt;
    &amp;lt;/QuerityComponentsProvider&amp;gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;A final look to the result:&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%2Feoaf2dhscfibiqocspsy.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%2Feoaf2dhscfibiqocspsy.png" width="800" height="557"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Querity React Components styled with Tailwind CSS&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In a similar way, you could instead integrate MUI components, that have a totally different way of declaration.&lt;br&gt;&lt;br&gt;
Querity React Components makes the job easy!&lt;/p&gt;

&lt;p&gt;See it in action at &lt;a href="https://querity-demo.onrender.com" rel="noopener noreferrer"&gt;Querity Demo&lt;/a&gt;… and of course find the code in the &lt;a href="https://github.com/queritylib/querity-demo" rel="noopener noreferrer"&gt;querity-demo GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you enjoyed this post about @queritylib/react, please don’t forget to&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/queritylib/querity-react" rel="noopener noreferrer"&gt;&lt;strong&gt;give it a⭐ on Github&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Querity React Components bridge the gap between your frontend and Querity-powered backend, enabling the creation of sophisticated query interfaces with minimal effort. By leveraging these components, you can provide users with powerful tools to interact with data, enhancing the overall user experience.&lt;/p&gt;

&lt;p&gt;Explore the full documentation and get started with Querity React Components today:&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@queritylib/react" rel="noopener noreferrer"&gt;@queritylib/react on npm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you missed the first article about the Java backend with Querity, you can find it here: &lt;a href="https://dev.to/brunomendola/easily-query-sql-and-nosql-databases-in-your-java-application-with-one-single-language-3ile-temp-slug-6999644"&gt;Easily query SQL and NoSQL databases in your Java application with one single language&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>typescript</category>
      <category>softwareengineering</category>
      <category>java</category>
    </item>
    <item>
      <title>Easily query SQL and NoSQL databases in your Java application with one single language</title>
      <dc:creator>Bruno Mendola</dc:creator>
      <pubDate>Thu, 13 Mar 2025 19:07:37 +0000</pubDate>
      <link>https://dev.to/brunomendola/easily-query-sql-and-nosql-databases-in-your-java-application-with-one-single-language-4g1</link>
      <guid>https://dev.to/brunomendola/easily-query-sql-and-nosql-databases-in-your-java-application-with-one-single-language-4g1</guid>
      <description>&lt;p&gt;In this article you will get to know &lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;Querity&lt;/a&gt;, an open source Java query builder for SQL and NoSQL, and hopefully discover that it can be useful for you.&lt;/p&gt;

&lt;p&gt;Of course you’ve already created some Java web application that expose some REST APIs to query a database, right?&lt;/p&gt;

&lt;p&gt;Let’s say that your frontend is something like this, and you have to create a backend with REST APIs to provide the data to display:&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%2Fdvlbfgbcw4vw61l1ykwt.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%2Fdvlbfgbcw4vw61l1ykwt.png" width="800" height="342"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Example of a frontend application with data displayed in a grid&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With Java and Spring Web / Spring Data is easy: use Spring Initializr to create a draft application, add a JPA entity, a JpaRepository and you’re good to go.&lt;/p&gt;

&lt;p&gt;Ok, let’s see some code!&lt;/p&gt;

&lt;p&gt;A Maven configuration file (pom.xml)…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;
  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
  &amp;lt;parent&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.4.3&amp;lt;/version&amp;gt;
    &amp;lt;relativePath/&amp;gt; &amp;lt;!-- lookup parent from repository --&amp;gt;
  &amp;lt;/parent&amp;gt;

  &amp;lt;groupId&amp;gt;my.demo&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;spring-data-jpa&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;

  &amp;lt;name&amp;gt;spring-data-jpa-demo&amp;lt;/name&amp;gt;
  &amp;lt;description&amp;gt;spring-data-jpa-demo&amp;lt;/description&amp;gt;

  &amp;lt;properties&amp;gt;
    &amp;lt;java.version&amp;gt;21&amp;lt;/java.version&amp;gt;
  &amp;lt;/properties&amp;gt;

  &amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-boot-starter-data-jpa&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;

    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
      &amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
    &amp;lt;/dependency&amp;gt;

    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;com.h2database&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;h2&amp;lt;/artifactId&amp;gt;
      &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
    &amp;lt;/dependency&amp;gt;
  &amp;lt;/dependencies&amp;gt;

  &amp;lt;build&amp;gt;
    &amp;lt;plugins&amp;gt;
      &amp;lt;plugin&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
      &amp;lt;/plugin&amp;gt;
    &amp;lt;/plugins&amp;gt;
  &amp;lt;/build&amp;gt;

&amp;lt;/project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a Spring Boot Application class…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootApplication
public class MyApplication {
  public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what you’ll get for free using &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initializr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By now you’ll have a ready-to-run empty application connected to an H2 in-memory database. Let’s fill it!&lt;/p&gt;

&lt;p&gt;We add a JPA entity…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Entity
@Table(name = "`order`")
@Getter @Setter
@EqualsAndHashCode(callSuper = true)
@ToString
public class Order extends AbstractPersistable&amp;lt;Long&amp;gt; {
  private Long orderNumber;
  private ZonedDateTime placementDate;
  private Currency currency;
  private BigDecimal totalPrice;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a JPA repository…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Repository
public interface OrderRepository extends 
    JpaRepository&amp;lt;Order, Long&amp;gt;, JpaSpecificationExecutor&amp;lt;Order&amp;gt; {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a data structure for our response…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public record Result&amp;lt;T&amp;gt;(List&amp;lt;T&amp;gt; items, long totalCount) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a service for our business logic…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class OrderService {
  private final OrderRepository repository;

  private OrderService(OrderRepository repository) {
    this.repository = repository;
  }

  public Result&amp;lt;Order&amp;gt; getOrders(int page, int pageSize) {
    Page&amp;lt;Order&amp;gt; orders = repository.findAll(PageRequest.of(page - 1, pageSize));
    return new Result&amp;lt;&amp;gt;(orders.toList(), orders.getTotalElements());
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a REST controller to handle HTTP requests to a GET endpoint…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
@RequestMapping("/api/orders")
public class OrderController {
  private final OrderService service;

  public OrderController(OrderService service) {
    this.service = service;
  }

  @GetMapping
  public Result&amp;lt;Order&amp;gt; getOrders(
      @RequestParam int page, @RequestParam int pageSize) {
    return service.getOrders(page, pageSize);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Directly exposing the JPA entities from the controller may not be a good idea, because it forces you to keep the transaction open for the duration of the request; usually you want to map the entities to DTO (data transfer object) classes in your service.&lt;br&gt;&lt;br&gt;
But let’s keep it simple for now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Start the application with ./mvnw spring-boot:run and your application will be up and running in your local host.&lt;/p&gt;

&lt;p&gt;Just a simple test with cURL…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/api/orders?page=1&amp;amp;pageSize=20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you’ll get a JSON response 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;{"items":[],"totalCount":0}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fair enough… the database is empty. But you get the point.&lt;/p&gt;

&lt;p&gt;We have a REST API that returns a paginated list of orders.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spoiler: if you’ll get to the end of the article, you’ll find the link to the repo of the demo application, that has an in-memory database with 1000 records.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Welcome to the real world
&lt;/h3&gt;

&lt;p&gt;Usually, in a real world scenario you need to &lt;strong&gt;filter&lt;/strong&gt; the orders by some value of the entity fields.&lt;/p&gt;

&lt;p&gt;Cool. You add some more query parameters to the API, and then your service will have to invoke the repository by passing the filtering info.&lt;/p&gt;

&lt;p&gt;In Spring Data JPA this is done with a &lt;strong&gt;Specification&lt;/strong&gt;. So your service method will become something 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;public Result&amp;lt;Order&amp;gt; getOrders(Long orderNumber,
                               ZonedDateTime placementDateFrom, ZonedDateTime placementDateTo,
                               Currency currency,
                               BigDecimal totalPriceFrom, BigDecimal totalPriceTo,
                               int page, int pageSize) {
  Specification&amp;lt;Order&amp;gt; specification = (root, query, criteriaBuilder) -&amp;gt; {
    List&amp;lt;Predicate&amp;gt; predicates = new ArrayList&amp;lt;&amp;gt;();
    if(orderNumber != null)
      predicates.add(criteriaBuilder.equal(root.get("orderNumber"), orderNumber));
    if(placementDateFrom != null)
      predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("placementDate"), placementDateFrom));
    if(placementDateTo != null)
      predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("placementDate"), placementDateTo));
    if(currency != null)
      predicates.add(criteriaBuilder.equal(root.get("currency"), currency));
    if(totalPriceFrom != null)
      predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("totalPrice"), totalPriceFrom));
    if(totalPriceTo != null)
      predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("totalPrice"), totalPriceTo));
    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
  };
  Page&amp;lt;Order&amp;gt; orders = repository.findAll(specification, PageRequest.of(page - 1, pageSize));
  return new Result&amp;lt;&amp;gt;(orders.toList(), orders.getTotalElements());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, but consider that this is a &lt;strong&gt;very simplified&lt;/strong&gt; entity class with 4 fields only.&lt;/p&gt;

&lt;p&gt;Now think to do this for all the fields of a “real world entity class”, then remember to update the filter every time you add a new field, also support filtering by nested fields (for example on order rows), and finally support the sorting of the results.&lt;/p&gt;

&lt;p&gt;It’s starting to look like a less simple task.&lt;/p&gt;

&lt;p&gt;Also the REST API documentation will be messy at that point… how many parameters can you add before it being unreadable?&lt;/p&gt;

&lt;h3&gt;
  
  
  Here comes Querity
&lt;/h3&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%2Fhzmzt20fnaxdjnqotvgh.jpeg" 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%2Fhzmzt20fnaxdjnqotvgh.jpeg" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;Querity&lt;/a&gt; is a &lt;strong&gt;Java query builder&lt;/strong&gt; that helps you querying the database with &lt;strong&gt;one simple query language&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It works with &lt;strong&gt;SQL databases&lt;/strong&gt; (like the one in this example) and &lt;strong&gt;NoSQL databases&lt;/strong&gt; such as &lt;strong&gt;MongoDB&lt;/strong&gt; and &lt;strong&gt;Elasticsearch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You don’t have to manage a REST API that gets more and more complex, you don’t have to continuously change your business logic when you add more fields… with Querity you will immediately get &lt;strong&gt;filtering, sorting and pagination&lt;/strong&gt; with very few lines of code.&lt;/p&gt;

&lt;p&gt;Just add the depedencies to your project…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;io.github.queritylib&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;querity-spring-data-jpa&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;3.1.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;io.github.queritylib&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;querity-parser&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;3.1.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your REST controller can be immediately simplified by having only one query string as request parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@GetMapping
public Result&amp;lt;Order&amp;gt; getOrders(
          @RequestParam(name = "q", required = false) String query) {
  return service.getOrders(query);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your service is also greatly simplified, because all the logic of creating the Specification is inside Querity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//...
import io.github.queritylib.querity.api.Querity;
import io.github.queritylib.querity.api.Query;
import io.github.queritylib.querity.parser.QuerityParser;
//...

@Service
public class OrderService {
  private final Querity querity;

  public OrderService(Querity querity) {
    this.querity = querity;
  }

  @Transactional(readOnly = true)
  public Result&amp;lt;Order&amp;gt; getOrders(String query) {
    Query q = query != null ?       
        QuerityParser.parseQuery(query) : // parse query language
        Query.builder().build(); // create an empty query if null
    List&amp;lt;Order&amp;gt; items = querity.findAll(Order.class, q);
    Long totalCount = querity.count(Order.class, q.getFilter());
    return new Result&amp;lt;&amp;gt;(items, totalCount);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll never need to touch that method again. Why? Because the query string that you’re receiving from the REST API can do &lt;strong&gt;filtering, sorting and pagination&lt;/strong&gt; on whatever field is inside your entity!&lt;/p&gt;

&lt;p&gt;Let’s complicate the domain model to see the real advantages. We will add order rows and customer infos…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Entity
@Table(name = "`order`")
@Getter @Setter
@EqualsAndHashCode(callSuper = true)
@ToString(exclude = "rows")
public class Order extends AbstractPersistable&amp;lt;Long&amp;gt; {
  private Long orderNumber;
  private ZonedDateTime placementDate;
  private String ipAddress;
  private Currency currency;
  @JoinColumn(name = "billing_customer_id", referencedColumnName = "id")
  @OneToOne(cascade = CascadeType.ALL)
  private CustomerInfo billingCustomer;
  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "shipping_customer_id", referencedColumnName = "id")
  private CustomerInfo shippingCustomer;
  @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
  private List&amp;lt;OrderRow&amp;gt; rows = new ArrayList&amp;lt;&amp;gt;();
  private BigDecimal totalPrice;
}

@Entity
@Getter @Setter
@EqualsAndHashCode(callSuper = true)
@ToString(exclude = "order")
public class OrderRow extends AbstractPersistable&amp;lt;Long&amp;gt; {
  @ManyToOne
  @JsonIgnore
  private Order order;
  private Long rowNumber;
  private String sku;
  private String description;
  private Long quantity;
  private BigDecimal unitPrice;
  private BigDecimal totalPrice;
}

@Entity
@Getter @Setter
@EqualsAndHashCode(callSuper = true)
@ToString
public class CustomerInfo extends AbstractPersistable&amp;lt;Long&amp;gt; {
  private String firstName;
  private String lastName;
  private String email;
  @Embedded
  private Address address;

  @Embeddable
  @Getter @Setter
  @EqualsAndHashCode
  @ToString
  public static class Address {
    private String streetAddress;
    private String city;
    private String postalCode;
    private String country;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our domain model now looks 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%2Ffcgl1gi9z15yd05yu8gg.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%2Ffcgl1gi9z15yd05yu8gg.png" alt="Updated domain model with order, order rows and customer info" width="800" height="1317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without implementing any new line of code, we are now be able to run this kind of queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;orderNumber=500

placementDate&amp;gt;="2024-07-01T00:00:00.000Z" page 1,10

shippingCustomer.address.country="Italy"

distinct and(rows.totalPrice&amp;gt;1000,currency="EUR") sort by placementDate desc page 1,20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we’re even able to &lt;strong&gt;filter by nested fields&lt;/strong&gt; , like the order rows price or the shipping country.&lt;/p&gt;

&lt;p&gt;Querity has a lot of other features, and this article is not big enough to cover all of them in detail. Just to mention two of them, there’s a module to &lt;strong&gt;support queries deserialization from JSON&lt;/strong&gt; in Spring Web MVC; and also &lt;strong&gt;support for DTOs&lt;/strong&gt; , because you may not want to expose the database entities to the presentation layer.&lt;/p&gt;

&lt;p&gt;We’ve used a SQL database and JPA for this tutorial, but you can switch to MongoDB or Elasticsearch just by changing the imported module. The query language will not change.&lt;/p&gt;

&lt;p&gt;Even Spring is not mandatory: if you have a Jakarta EE application, you can import the querity-jpa module and leverage the plain Jakarta Persistence API.&lt;/p&gt;

&lt;p&gt;A Java DSL is also available to &lt;strong&gt;create queries with a fluent syntax&lt;/strong&gt; , so you can easily use Querity for your internal business logic.&lt;br&gt;&lt;br&gt;
Just 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;Query query = Querity.query()
    .distinct(true)
    .filter(
      and(
        filterBy("rows.totalPrice", GREATER_THAN, 1000),
        filterBy("currency", EQUALS, "EUR")
      )
    )
    .sort(sortBy("placementDate", DESC))
    .pagination(1, 20)
    .build();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;If you think that &lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;Querity&lt;/a&gt; could be useful for you, &lt;a href="https://github.com/queritylib/querity" rel="noopener noreferrer"&gt;&lt;strong&gt;give it a⭐ on Github&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The full &lt;a href="https://queritylib.github.io/querity/" rel="noopener noreferrer"&gt;&lt;strong&gt;Querity documentation&lt;/strong&gt;&lt;/a&gt; is available in its own website, with all the details about the features and the query language.&lt;/p&gt;

&lt;p&gt;Last but not least, you can also see the code of the &lt;a href="https://github.com/queritylib/querity-demo" rel="noopener noreferrer"&gt;&lt;strong&gt;Querity demo&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;application&lt;/strong&gt; that inspired this post.&lt;/p&gt;

&lt;p&gt;Have fun! 😎&lt;/p&gt;

</description>
      <category>sql</category>
      <category>springboot</category>
      <category>nosql</category>
      <category>querybuilder</category>
    </item>
  </channel>
</rss>
