<?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: David | Kordhub</title>
    <description>The latest articles on DEV Community by David | Kordhub (@kordhubdev).</description>
    <link>https://dev.to/kordhubdev</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%2F4011223%2F414bb6a5-9fb3-4b41-a318-b0a4fa865d9c.png</url>
      <title>DEV Community: David | Kordhub</title>
      <link>https://dev.to/kordhubdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kordhubdev"/>
    <language>en</language>
    <item>
      <title>3 FastAPI Services, 1 Process: The Bugs Nobody Warns You About published: false tags: fastapi, python, api, webdev</title>
      <dc:creator>David | Kordhub</dc:creator>
      <pubDate>Mon, 03 Aug 2026 16:01:53 +0000</pubDate>
      <link>https://dev.to/kordhubdev/3-fastapi-services-1-process-the-bugs-nobody-warns-you-about-published-false-tags-fastapi-57oa</link>
      <guid>https://dev.to/kordhubdev/3-fastapi-services-1-process-the-bugs-nobody-warns-you-about-published-false-tags-fastapi-57oa</guid>
      <description>&lt;p&gt;I had three independent FastAPI services, each with its own repo and its own deployment, and I wanted to merge them into a single process — one app, three mounted sub-apps. On paper it's a five-line change: import each app, &lt;code&gt;app.mount()&lt;/code&gt; it under a prefix, done.&lt;/p&gt;

&lt;p&gt;In practice, it surfaced three bugs I wouldn't have hit any other way — and they're the kind of bugs that only show up once code that worked fine in isolation has to share a process with siblings it's never met.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Three independent APIs, each its own repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discord Webhook Shield&lt;/strong&gt; — stores Discord webhook URLs encrypted, proxies messages through with spam filtering and optional AI-based formatting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QR Code Generator&lt;/strong&gt; — PNG/SVG generation with logo overlay&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON Repair&lt;/strong&gt; — fixes malformed JSON from LLM output, falling back to an AI repair pass when the deterministic parser can't handle it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Merging them meant mounting all three as FastAPI sub-applications under one root app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;webhook_shield.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;webhook_shield_app&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;qr_generator.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;qr_generator_app&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;json_fixer.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;json_repair_app&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Kordhub API Suite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/webhook-shield&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;webhook_shield_app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/qr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qr_generator_app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/json-repair&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_repair_app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Straightforward. Then I actually ran it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug #1: a package shadowing its own dependency
&lt;/h2&gt;

&lt;p&gt;The JSON repair service imports the &lt;code&gt;json_repair&lt;/code&gt; library (&lt;code&gt;from json_repair import repair_json&lt;/code&gt;). I'd named its own package folder &lt;code&gt;json_repair&lt;/code&gt; too, for symmetry with the other two. Python resolved the local package first, and the import inside it silently broke — a name collision that only exists once you put sibling services in the same interpreter. Renamed the folder to &lt;code&gt;json_fixer&lt;/code&gt;, problem gone. Obvious in hindsight, invisible until you actually boot the merged process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug #2: &lt;code&gt;.env&lt;/code&gt; files stomping on each other
&lt;/h2&gt;

&lt;p&gt;Each service loaded its own &lt;code&gt;.env&lt;/code&gt; the same way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dotenv_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.env&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;python-dotenv&lt;/code&gt;'s &lt;code&gt;load_dotenv()&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; override a variable that's already set in the process environment — by default. That's fine when each service is its own process. It's not fine when three services share one process and all three &lt;code&gt;.env&lt;/code&gt; files define a key with the &lt;em&gt;same name&lt;/em&gt; (&lt;code&gt;RAPIDAPI_PROXY_SECRET&lt;/code&gt;, in my case, each with a different value). Whichever module imports first "wins," and the other two silently validate against the wrong secret.&lt;/p&gt;

&lt;p&gt;The minimal fix was &lt;code&gt;override=True&lt;/code&gt; on each &lt;code&gt;load_dotenv()&lt;/code&gt; call, so each module's own file takes precedence at the moment it loads. But that only solves it for local development, where each sub-package still has its own &lt;code&gt;.env&lt;/code&gt; file. On a platform like Render, environment variables are injected once, process-wide — there's no such thing as three separate &lt;code&gt;.env&lt;/code&gt; files anymore. So the real fix was to stop sharing the variable &lt;em&gt;name&lt;/em&gt; at all: each sub-app now reads its own uniquely-named secret (&lt;code&gt;WEBHOOK_SHIELD_PROXY_SECRET&lt;/code&gt;, &lt;code&gt;QR_GENERATOR_PROXY_SECRET&lt;/code&gt;, &lt;code&gt;JSON_FIXER_PROXY_SECRET&lt;/code&gt;), each still validated against the exact proxy secret RapidAPI already had configured for that specific API listing. No changes needed on RapidAPI's side, and the three services never have to agree on anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug #3: fail-fast code that fails the wrong thing
&lt;/h2&gt;

&lt;p&gt;One of the services calls &lt;code&gt;sys.exit(1)&lt;/code&gt; if a required credential is missing at import time — reasonable for a standalone service, since you want a fast, loud failure instead of serving broken requests. Reasonable, until it's one FastAPI sub-app mounted inside a bigger process: a missing variable now takes down all three APIs, not just the one that needed it. I left the fail-fast behavior in place (it's still the right call), but it's now a hard requirement that &lt;em&gt;every&lt;/em&gt; environment variable for &lt;em&gt;all three&lt;/em&gt; services be set together in the merged deployment — a constraint that didn't exist when they were separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually mattered
&lt;/h2&gt;

&lt;p&gt;None of these were algorithm problems. They were all "two things that work fine alone don't automatically work fine together" problems — namespace collisions, shared process state, and failure modes that assume isolation. The lesson that generalizes: when you consolidate services that were never designed to share a process, test the &lt;em&gt;combination&lt;/em&gt;, not just each piece. A health check on each mounted sub-app told me nothing about the env var collision — only calling a real authenticated endpoint on each one, with distinct test values, actually caught it.&lt;/p&gt;

&lt;p&gt;The three APIs are live again, now sharing a single Render free-tier instance instead of three:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-discord-webhook-shield-formatter" rel="noopener noreferrer"&gt;Discord Webhook Shield &amp;amp; Formatter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-qr-code-generator" rel="noopener noreferrer"&gt;QR Code Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-ai-json-repair-formatter" rel="noopener noreferrer"&gt;AI JSON Repair &amp;amp; Formatter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Curious how others have handled merging previously-independent services into one deployment — did you run into the same class of "works alone, breaks together" bugs, or something else entirely?&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Generating branded QR codes with logo overlay in Python (PNG + SVG)</title>
      <dc:creator>David | Kordhub</dc:creator>
      <pubDate>Mon, 06 Jul 2026 13:17:52 +0000</pubDate>
      <link>https://dev.to/kordhubdev/generating-branded-qr-codes-with-logo-overlay-in-python-png-svg-5ei6</link>
      <guid>https://dev.to/kordhubdev/generating-branded-qr-codes-with-logo-overlay-in-python-png-svg-5ei6</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Most QR code libraries give you a black-and-white square. &lt;br&gt;
That's fine for internal tools, but if you need branded QR codes &lt;br&gt;
for marketing, packaging, or invoices, you need custom colors, &lt;br&gt;
your logo in the center, SVG output for print quality, and high &lt;br&gt;
enough error correction that the QR still scans with a logo on top.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why error correction matters for logo overlay
&lt;/h2&gt;

&lt;p&gt;When you put a logo in the center of a QR code, you're covering &lt;br&gt;
part of the data. QR codes have built-in error correction — &lt;br&gt;
level H (30%) means the code can still be read even if 30% of it &lt;br&gt;
is obscured. Always use H when adding a logo.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generating a branded QR code
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/generate&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;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://yoursite.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"foreground_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#2563EB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#FFFFFF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error_correction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"H"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logo_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://yoursite.com/logo.png"&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;Response — the &lt;code&gt;data&lt;/code&gt; field is base64-encoded PNG:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"data:image/png;base64,iVBORw0KGgo..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PNG vs SVG
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PNG&lt;/strong&gt; — best for web, apps, and mobile. Supports logo overlay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SVG&lt;/strong&gt; — best for print and packaging. Scales infinitely without pixelation. No logo overlay support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate before generating
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;/validate&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;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your string here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error_correction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"H"&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;Response:&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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estimated_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QR version 4 will be used"&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;Higher version = denser QR. Version 40 is the maximum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it free
&lt;/h2&gt;

&lt;p&gt;500 requests/month, no card required:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-qr-code-generator" rel="noopener noreferrer"&gt;https://rapidapi.com/kordhubdev/api/kordhub-qr-code-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome — especially if you've found edge cases with logo overlay or very long URLs.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I protect Discord webhook URLs from being exposed in frontend code</title>
      <dc:creator>David | Kordhub</dc:creator>
      <pubDate>Fri, 03 Jul 2026 21:30:35 +0000</pubDate>
      <link>https://dev.to/kordhubdev/how-i-protect-discord-webhook-urls-from-being-exposed-in-frontend-code-2ha6</link>
      <guid>https://dev.to/kordhubdev/how-i-protect-discord-webhook-urls-from-being-exposed-in-frontend-code-2ha6</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;If you've ever used Discord webhooks in a frontend app, you've probably done something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webhookUrl = "https://discord.com/api/webhooks/123456/abc..."
fetch(webhookUrl, { method: "POST", body: JSON.stringify(message) })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The problem: that URL is now visible to anyone who opens DevTools. &lt;br&gt;
They can use it to spam your Discord server, send fake alerts, &lt;br&gt;
or simply abuse it until Discord revokes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Never expose the real URL
&lt;/h2&gt;

&lt;p&gt;The pattern that actually works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register your webhook URL once through a secure backend&lt;/li&gt;
&lt;li&gt;Get back a safe ID (like &lt;code&gt;whk_abc123&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Use only that ID in your frontend — the real URL never leaves the server&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How it works in practice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Register once (server-side or one-time setup):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v1/webhooks
{ "discord_webhook_url": "https://discord.com/api/webhooks/..." }

Response: { "webhook_id": "whk_abc123" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Send messages using only the ID:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v1/send
{
  "webhook_id": "whk_abc123",
  "content": "New sale: $49.99",
  "title": "Payment received",
  "mode": "auto"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The server decrypts the real URL, formats the message into a &lt;br&gt;
clean Discord embed, strips any &lt;a class="mentioned-user" href="https://dev.to/everyone"&gt;@everyone&lt;/a&gt;/&lt;a class="mentioned-user" href="https://dev.to/here"&gt;@here&lt;/a&gt; spam, and delivers it.&lt;br&gt;
Your frontend never sees the real webhook URL again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: automatic spam filtering
&lt;/h2&gt;

&lt;p&gt;Even if someone on your team accidentally sends &lt;a class="mentioned-user" href="https://dev.to/everyone"&gt;@everyone&lt;/a&gt; in &lt;br&gt;
an automated message, the API strips it before it reaches Discord.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it free
&lt;/h2&gt;

&lt;p&gt;I built this as a standalone API available on RapidAPI with a &lt;br&gt;
free tier (200 messages/month, no card required):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-discord-webhook-shield-formatter" rel="noopener noreferrer"&gt;https://rapidapi.com/kordhubdev/api/kordhub-discord-webhook-shield-formatter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love feedback — especially from anyone who's dealt with &lt;br&gt;
webhook abuse before.&lt;/p&gt;

</description>
      <category>discord</category>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>I built 3 free APIs for LLM developers — here's what I shipped and why</title>
      <dc:creator>David | Kordhub</dc:creator>
      <pubDate>Wed, 01 Jul 2026 17:23:53 +0000</pubDate>
      <link>https://dev.to/kordhubdev/i-built-3-free-apis-for-llm-developers-heres-what-i-shipped-and-why-95c</link>
      <guid>https://dev.to/kordhubdev/i-built-3-free-apis-for-llm-developers-heres-what-i-shipped-and-why-95c</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;If you've built anything with GPT-4, Claude, or Llama, you've probably run into these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON that won't parse because of a trailing comma or markdown fence&lt;/li&gt;
&lt;li&gt;Discord webhook URLs exposed in your frontend code&lt;/li&gt;
&lt;li&gt;Needing QR codes dynamically but not wanting to pay per request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I kept hitting these same walls, so I spent a week building three utility APIs to solve them. All three have free tiers on RapidAPI.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. JSON Repair &amp;amp; Formatter
&lt;/h2&gt;

&lt;p&gt;LLMs don't always return clean JSON. Trailing commas, markdown code fences, truncated objects — all of these break JSON.parse() and crash your pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input (broken LLM output):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "name": "Pro Plan", "price": 19.00, }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output (clean JSON):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "name": "Pro Plan", "price": 19.00 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Fast local repair engine first (&amp;lt;5ms, no AI call). Falls back to AI only when the input is too corrupted for local processing.&lt;/p&gt;

&lt;p&gt;Free tier: 500 requests/month, no card required.&lt;br&gt;
&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-ai-json-repair-formatter" rel="noopener noreferrer"&gt;https://rapidapi.com/kordhubdev/api/kordhub-ai-json-repair-formatter&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Discord Webhook Shield &amp;amp; Formatter
&lt;/h2&gt;

&lt;p&gt;If you use Discord webhooks in a frontend app, your webhook URL is exposed in source code. Anyone can find it and spam your server.&lt;/p&gt;

&lt;p&gt;You register your real webhook URL once — stored encrypted — and get a safe webhook_id instead. Your real URL never touches your frontend again. Auto-strips &lt;a class="mentioned-user" href="https://dev.to/everyone"&gt;@everyone&lt;/a&gt;/&lt;a class="mentioned-user" href="https://dev.to/here"&gt;@here&lt;/a&gt; spam before anything reaches Discord.&lt;/p&gt;

&lt;p&gt;Free tier: 200 messages/month, no card required.&lt;br&gt;
&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-discord-webhook-shield-formatter" rel="noopener noreferrer"&gt;https://rapidapi.com/kordhubdev/api/kordhub-discord-webhook-shield-formatter&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. QR Code Generator
&lt;/h2&gt;

&lt;p&gt;PNG &amp;amp; SVG output, custom hex colors, optional logo overlay. Error correction up to H (30%) keeps the QR scannable even with a logo on top. 100% local processing — no per-call AI cost.&lt;/p&gt;

&lt;p&gt;Free tier: 500 requests/month, no card required.&lt;br&gt;
&lt;a href="https://rapidapi.com/kordhubdev/api/kordhub-qr-code-generator" rel="noopener noreferrer"&gt;https://rapidapi.com/kordhubdev/api/kordhub-qr-code-generator&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;p&gt;FastAPI + Python, hosted on Render. Local engines use open-source libraries (json-repair, qrcode + Pillow) so cost per request is near zero. Groq only kicks in as AI fallback when local processing fails.&lt;/p&gt;

&lt;p&gt;Would love feedback on pricing or use cases I missed.&lt;br&gt;
Find me on X: @kordhub&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>llm</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
