<?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: Sujal Khatri</title>
    <description>The latest articles on DEV Community by Sujal Khatri (@sujalkhatri).</description>
    <link>https://dev.to/sujalkhatri</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%2F4185212%2F5f3e44c8-2409-4771-89d7-4043348e95cb.jpg</url>
      <title>DEV Community: Sujal Khatri</title>
      <link>https://dev.to/sujalkhatri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sujalkhatri"/>
    <language>en</language>
    <item>
      <title>JSON Validator &amp; Formatter: How to Fix Invalid JSON Fast (Without Installing Anything)</title>
      <dc:creator>Sujal Khatri</dc:creator>
      <pubDate>Fri, 16 Oct 2026 21:04:28 +0000</pubDate>
      <link>https://dev.to/sujalkhatri/json-validator-formatter-how-to-fix-invalid-json-fast-without-installing-anything-11f1</link>
      <guid>https://dev.to/sujalkhatri/json-validator-formatter-how-to-fix-invalid-json-fast-without-installing-anything-11f1</guid>
      <description>&lt;p&gt;JSON is everywhere — APIs, config files, package.json — and it breaks in the most annoying ways. Here are the 5 errors I see most often, and the fastest ways to find and fix them without installing anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Trailing commas
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sujal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jaipur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That comma after &lt;code&gt;"Jaipur"&lt;/code&gt; kills the whole file. JSON does not allow trailing commas, period. Delete it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Single quotes instead of double quotes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'name':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Sujal'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks fine, is not JSON. Keys AND string values must use double quotes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sujal"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Unquoted keys
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sujal"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Valid JavaScript object, invalid JSON. Quote every key.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Comments
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;details&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sujal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JSON has no comments. If you need them, use JSONC in your editor — but strip them before sending to an API.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. NaN, Infinity, undefined
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;NaN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are JavaScript things, not JSON things. Use &lt;code&gt;null&lt;/code&gt; or a number.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fastest ways to validate
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Browser console (zero setup):&lt;/strong&gt; paste your JSON into &lt;code&gt;JSON.parse('...')&lt;/code&gt;. The error message tells you the exact character position where it broke. That's usually enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python (already on most machines):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"a":1,}'&lt;/span&gt; | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It pretty-prints valid JSON and points at the error for invalid JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jq (if you live in the terminal):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"a":1}'&lt;/span&gt; | jq &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Formatting: pick one style and stick to it
&lt;/h2&gt;

&lt;p&gt;2-space indent is the most common. Tabs are fine too. What matters is consistency — mixed indentation makes diffs unreadable and code reviews painful.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real before/after
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;'users':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Amit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;age:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;name:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Priya'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;age:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Amit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Priya"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four fixes: quotes, keys, trailing commas, and it's done.&lt;/p&gt;




&lt;p&gt;I got tired of switching between five different sites for this kind of work, so I built BulkTextKit — 15 free text tools in the browser, including a JSON formatter/validator that points at the exact error. Pro (batch processing, presets, CSV export) is $9 until Oct 19: &lt;a href="https://bulktextkit.gt.tc" rel="noopener noreferrer"&gt;https://bulktextkit.gt.tc&lt;/a&gt;&lt;/p&gt;

</description>
      <category>json</category>
      <category>webdev</category>
      <category>tools</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I built 15 free text tools with plain PHP and zero APIs — here's what I learned</title>
      <dc:creator>Sujal Khatri</dc:creator>
      <pubDate>Wed, 14 Oct 2026 17:34:12 +0000</pubDate>
      <link>https://dev.to/sujalkhatri/i-built-15-free-text-tools-with-plain-php-and-zero-apis-heres-what-i-learned-18kh</link>
      <guid>https://dev.to/sujalkhatri/i-built-15-free-text-tools-with-plain-php-and-zero-apis-heres-what-i-learned-18kh</guid>
      <description>&lt;p&gt;This week I launched a new product: BulkTextKit, a set of 15 free text tools — word counter, case converter, JSON formatter/validator, regex tester, slug generator, and more — that run entirely in your browser. No signup, no uploads, no tracking. I'm a solo maker in India, I build with plain PHP + MySQL, and I made one unusual choice on purpose: zero third-party APIs. Everything the tools do happens in client-side JavaScript; the server only renders pages and handles the Pro license flow through PayPal. In this post I'll walk through why I chose that architecture, how the build went, and the one-time pricing model I'm betting on instead of yet another subscription.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem I kept hitting
&lt;/h2&gt;

&lt;p&gt;Every day I run into the same tiny text chores: counting words in client copy, converting a heading to title case, stripping duplicate lines from a messy list, or checking whether a snippet of JSON is actually valid. These jobs take a minute each, but they pile up when you work with words all day.&lt;/p&gt;

&lt;p&gt;The free tools I found online were scattered across dozens of ad-heavy pages, and most of them sent my text to some server I knew nothing about. I stopped trusting them for anything sensitive, which meant I kept doing these chores by hand or wiring up throwaway scripts. That friction is the problem BulkTextKit exists to erase: one fast page, fifteen tools, nothing leaves your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why PHP + zero APIs
&lt;/h2&gt;

&lt;p&gt;One deliberate decision shaped the whole product: zero third-party APIs. No API keys means nothing to leak, nothing to rotate, and no third-party service that can be shut down, rate-limited, or bought and sunsetted underneath me.&lt;/p&gt;

&lt;p&gt;It also means the site runs on cheap shared hosting with plain PHP and MySQL. There is no build pipeline, no framework to keep updated, and no SDK that can break a deploy. For a solo maker in India, boring infrastructure is a feature, not a compromise.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the tools work
&lt;/h2&gt;

&lt;p&gt;All fifteen tools run 100% in browser JavaScript — Word Counter, Case Converter, Remove Duplicate Lines, JSON Formatter &amp;amp; Validator, Regex Tester, Slug Generator, Lorem Ipsum Generator, Text Diff, CSV to Columns, Remove Line Breaks, Word Frequency Counter, Base64 Encoder/Decoder, Markdown Table Generator, Strip HTML, and Password Generator.&lt;/p&gt;

&lt;p&gt;PHP only renders the pages and handles the Pro license flow, including the PayPal IPN handshake that activates a purchase. Your text never touches my server, which is exactly the point: you can paste client work into these tools without wondering where it went.&lt;/p&gt;

&lt;h2&gt;
  
  
  The business model
&lt;/h2&gt;

&lt;p&gt;All fifteen tools are free forever — that is the product, not a trial. Pro is a one-time payment of $9 during the 72-hour launch offer (regular price $19), unlocking bulk/batch mode for up to 50 texts at once, saved presets for repeat tasks, and CSV export. Checkout is via PayPal, and every purchase is covered by a 7-day money-back guarantee.&lt;/p&gt;

&lt;p&gt;I am betting on one-time pricing instead of yet another subscription because these are small utilities, not a platform. The launch offer is live now at &lt;a href="https://bulktextkit.gt.tc" rel="noopener noreferrer"&gt;BulkTextKit&lt;/a&gt; — try the free tools and tell me: which tool should I add next?&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;p&gt;If I built this again, I would start marketing much earlier. I waited until launch week to talk about it publicly, which meant I launched to no audience at all. I would also ship smaller: instead of polishing fifteen tools before telling anyone, I would have launched with five and let feedback pick the rest.&lt;/p&gt;

&lt;p&gt;Both lessons point the same way: build in the open from day one. I am starting now, so expect to see more of the process, not just the finished product.&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
