<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Web Dev - Category - Botmonster Tech</title><link>https://botmonster.com/web-dev/</link><description>Web Dev - Category - Botmonster Tech</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 11 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://botmonster.com/web-dev/" rel="self" type="application/rss+xml"/><item><title>URL Shortener in 200 Lines of Python</title><link>https://botmonster.com/web-dev/build-url-shortener-from-scratch-200-lines/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/build-url-shortener-from-scratch-200-lines/</guid><description><![CDATA[<div class="featured-image">
                <img src="/build-url-shortener-from-scratch-200-lines.png" referrerpolicy="no-referrer">
            </div><p>I&rsquo;ll show you how to build a real URL shortener in under 200 lines of Python. We&rsquo;re going to use FastAPI for the web layer, <a href="https://www.sqlite.org/" target="_blank" rel="noopener noreferrer ">SQLite</a>
 for storage, and base62 encoding for short codes. I&rsquo;ll walk you through a redirect endpoint, a click counter, and rate limiting with <a href="https://slowapi.readthedocs.io/" target="_blank" rel="noopener noreferrer ">SlowAPI</a>
. In my experience, this simple stack handles millions of links on one server.</p>
<section class="key-takeaways">
  <h2 id="key-takeaways" class="key-takeaways-title">
    <svg class="key-takeaways-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
      <rect x="4" y="3" width="16" height="18" rx="2" ry="2"></rect>
      <path d="M8 8h5"></path>
      <path d="M8 13h8"></path>
      <path d="M8 17h8"></path>
      <path d="M15.5 7l1.2 1.2L19 6"></path>
    </svg>
    <span>Key Takeaways</span>
  </h2>
  <div class="key-takeaways-body">
<ul>
<li>Build a production-ready URL shortener with fewer than 200 lines of Python.</li>
<li>Use SQLite for zero-config storage that handles thousands of requests per second.</li>
<li>Implement base62 encoding to turn database IDs into short, clean strings.</li>
<li>Protect your service with SlowAPI rate limiting to block spam bots.</li>
<li>Deploy the entire app in a 50 MB Docker container behind a Caddy reverse proxy.</li>
</ul>

  </div>
</section>

<h2 id="architecture-and-tech-stack-choices">Architecture and Tech Stack Choices</h2>
<p>Before I write any code, I want to walk you through why I picked this stack. Picking the wrong stack for a small project either over-engineers it or under-builds it. I&rsquo;ve seen systems fall over at a few hundred users, and I want to help you avoid that.</p>]]></description></item><item><title>SQLite at the Edge: 100x Faster Reads, Cloudflare D1 and LiteFS</title><link>https://botmonster.com/web-dev/sqlite-on-the-edge-serverless-cdn-environments/</link><pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/sqlite-on-the-edge-serverless-cdn-environments/</guid><description><![CDATA[<div class="featured-image">
                <img src="/sqlite-on-the-edge-serverless-cdn-environments.png" referrerpolicy="no-referrer">
            </div><p>SQLite can now run at the edge - inside <a href="https://workers.cloudflare.com/" target="_blank" rel="noopener noreferrer ">Cloudflare Workers</a>
 via D1, on <a href="https://fly.io/" target="_blank" rel="noopener noreferrer ">Fly.io</a>
 via LiteFS replicated volumes, and in any V8 isolate through embedded WASM builds. This gives you sub-millisecond read queries by placing your database physically close to your users on a global CDN. The key innovations that made this practical are LiteFS for transparent SQLite replication across distributed nodes, Cloudflare D1 as a managed edge SQLite service, <a href="https://turso.tech/" target="_blank" rel="noopener noreferrer ">Turso</a>
 with its libSQL fork adding server mode and built-in replication, and <a href="https://litestream.io/" target="_blank" rel="noopener noreferrer ">Litestream</a>
 for continuous WAL-based streaming to S3. Combined with SQLite&rsquo;s zero-dependency, single-file architecture, you get a relational database that deploys as part of your application binary, needs no connection pooling, and handles thousands of reads per second per node with microsecond-level latency.</p>]]></description></item><item><title>Python Markdown Blog: 100 Lines of Code</title><link>https://botmonster.com/web-dev/build-markdown-blog-engine-100-lines-python/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/build-markdown-blog-engine-100-lines-python/</guid><description><![CDATA[<div class="featured-image">
                <img src="/build-markdown-blog-engine-100-lines-python.png" referrerpolicy="no-referrer">
            </div><p>You can build a working static site generator in about 100 lines of Python. The result reads Markdown files from a content directory, parses their YAML front matter, converts the Markdown to HTML, wraps everything in Jinja2 templates, and writes the output to a <code>public/</code> folder ready to be served by any web server. It is the same fundamental pipeline that powers tools like <a href="https://gohugo.io/" target="_blank" rel="noopener noreferrer ">Hugo</a>
, <a href="https://jekyllrb.com/" target="_blank" rel="noopener noreferrer ">Jekyll</a>
, and <a href="https://www.11ty.dev/" target="_blank" rel="noopener noreferrer ">Eleventy</a>
 - just stripped down to the essentials so you can see exactly how the pieces fit together.</p>]]></description></item><item><title>WCAG 2.2 Web Forms: Error Handling, Validation, ARIA</title><link>https://botmonster.com/web-dev/accessible-web-forms-aria-validation-error-handling/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/accessible-web-forms-aria-validation-error-handling/</guid><description><![CDATA[<div class="featured-image">
                <img src="/accessible-web-forms-aria-validation-error-handling.png" referrerpolicy="no-referrer">
            </div><p>Accessible web forms start with semantic HTML and use ARIA only to fill gaps native elements can&rsquo;t reach. Use <code>aria-live</code> for error announcements and <code>aria-describedby</code> to link messages to fields. Following <a href="https://www.w3.org/WAI/standards-guidelines/wcag/" target="_blank" rel="noopener noreferrer ">WCAG</a>
 2.2 AA ensures every user can perceive, navigate, and complete your forms using only a keyboard.</p>
<p>Most form accessibility failures are not caused by missing ARIA. They come from developers skipping basic HTML semantics like labels and fieldsets. Patching this damage with ARIA often makes things worse. The W3C&rsquo;s first rule is simple: no ARIA is better than bad ARIA. Misapplied roles or redundant labels create noise instead of clarity.</p>]]></description></item><item><title>Monorepo Management with Turborepo: A Practical Guide</title><link>https://botmonster.com/web-dev/monorepo-management-turborepo-practical-guide/</link><pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/monorepo-management-turborepo-practical-guide/</guid><description><![CDATA[<div class="featured-image">
                <img src="/monorepo-management-turborepo-practical-guide.png" referrerpolicy="no-referrer">
            </div><p><a href="https://turbo.build/" target="_blank" rel="noopener noreferrer ">Turborepo</a>
 is a high-performance build system for JavaScript and TypeScript monorepos. It uses content-aware caching, parallel task execution, and dependency-aware task ordering to make multi-package repositories fast and practical to work with. You define your workspace packages in a <code>pnpm-workspace.yaml</code> file (or npm/yarn workspaces), configure a <code>turbo.json</code> that declares task dependencies and caching behavior, and Turborepo handles the rest. Running <code>turbo run build</code> only rebuilds packages whose source files have actually changed, with cache hits restoring build outputs in milliseconds instead of minutes.</p>]]></description></item><item><title>Type-Safe APIs with Pydantic v3 and FastAPI: A Best Practices Guide</title><link>https://botmonster.com/web-dev/type-safe-apis-pydantic-v3-fastapi-best-practices/</link><pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/type-safe-apis-pydantic-v3-fastapi-best-practices/</guid><description><![CDATA[<div class="featured-image">
                <img src="/customs-inspector-data-types.png" referrerpolicy="no-referrer">
            </div><p><a href="https://docs.pydantic.dev/latest/" target="_blank" rel="noopener noreferrer ">Pydantic v3</a>
 shipped in late 2025. It has a new Rust-backed core and a fresh model system. With <a href="https://fastapi.tiangolo.com/" target="_blank" rel="noopener noreferrer ">FastAPI</a>
 0.115+, you get auto request checks, fast JSON output, and OpenAPI 3.1 docs. No manual schema work. Data errors get caught at the API edge. Client SDKs come from the live spec. The check overhead that used to be a bottleneck is now mostly gone.</p>
<p>This guide walks through what changed in v3, how to lay out a production project, the validation patterns to know, and what deployment looks like when you care about speed.</p>]]></description></item><item><title>CSS Anchor Positioning: Replace Floating UI With CSS</title><link>https://botmonster.com/web-dev/css-anchor-positioning-tooltips-popovers/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/css-anchor-positioning-tooltips-popovers/</guid><description><![CDATA[<div class="featured-image">
                <img src="/css-anchor-positioning-tooltips-popovers.png" referrerpolicy="no-referrer">
            </div><p>CSS Anchor Positioning is a browser-native feature that pins any absolutely-placed element to another element in the document. No JavaScript required. With the <code>anchor()</code> function, <code>position-anchor</code> property, and <code>@position-try</code> rules, you can build tooltips, dropdown menus, and context menus in pure CSS and HTML. It now works in Chrome 125+, Firefox 132+, and Safari 18.2+, which covers about 91% of browser traffic. Pair it with the HTML <code>popover</code> attribute (Baseline 2024) and you get show/hide toggling, keyboard dismissal, and top-layer stacking for free. The JavaScript tooltip library is dead for most use cases.</p>]]></description></item><item><title>Implement OAuth 2.0 with PKCE: Flask + GitHub Login</title><link>https://botmonster.com/web-dev/implement-oauth-2-login-from-scratch/</link><pubDate>Mon, 13 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/implement-oauth-2-login-from-scratch/</guid><description><![CDATA[<div class="featured-image">
                <img src="/implement-oauth-2-login-from-scratch.png" referrerpolicy="no-referrer">
            </div><p>You implement OAuth 2.0 login by using the Authorization Code flow with PKCE (Proof Key for Code Exchange). Your web app redirects the user to the provider&rsquo;s authorization endpoint with a <code>code_challenge</code>, the user authenticates and consents, the provider redirects back with an authorization <code>code</code>, and your backend exchanges that code along with the <code>code_verifier</code> for an access token. PKCE is mandatory for all OAuth 2.0 clients under the <a href="https://oauth.net/2.1/" target="_blank" rel="noopener noreferrer ">OAuth 2.1 draft specification</a>
 (currently at draft-ietf-oauth-v2-1-15) and eliminates the need for a client secret in public clients. Building this from scratch - without Auth0, Clerk, or NextAuth - takes roughly 200 lines of code and teaches you exactly how token exchange, session management, and token refresh actually work.</p>]]></description></item><item><title>Tailwind v4: Oxide Rust Engine, 182x Incremental Builds, CSS Config</title><link>https://botmonster.com/web-dev/tailwind-css-v4-what-changed-how-to-migrate/</link><pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/tailwind-css-v4-what-changed-how-to-migrate/</guid><description><![CDATA[<div class="featured-image">
                <img src="/tailwind-css-v4-what-changed-how-to-migrate.png" referrerpolicy="no-referrer">
            </div><p>Tailwind CSS v4 is a ground-up rewrite. The JavaScript-based PostCSS plugin is gone, replaced by a Rust-powered engine called Oxide. Configuration moves from <code>tailwind.config.js</code> into CSS-native <code>@theme</code> directives. Full builds run up to 5x faster, incremental builds over 100x faster. The entry point is now a single <code>@import &quot;tailwindcss&quot;</code> line instead of three separate <code>@tailwind</code> directives. Most v3 projects can migrate in under an hour using the official <code>@tailwindcss/upgrade</code> codemod, but knowing what actually changed - and why - prevents surprises during the transition.</p>]]></description></item><item><title>Web Font Subsetting: Cut Payload by 90% with Variable Fonts</title><link>https://botmonster.com/web-dev/variable-fonts-subsetting-web-performance/</link><pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate><author>Botmonster</author><guid>https://botmonster.com/web-dev/variable-fonts-subsetting-web-performance/</guid><description><![CDATA[<div class="featured-image">
                <img src="/variable-fonts-subsetting-web-performance.png" referrerpolicy="no-referrer">
            </div><p>By subsetting a variable font with <code>pyftsubset</code> to include only the Unicode ranges and OpenType features your site actually needs, and serving it as a WOFF2 file with the CSS <code>unicode-range</code> descriptor, you can reduce web font payload by 70-85%. A typical setup drops a 300 KB variable font to under 40 KB while keeping full weight and italic axis support for every glyph you actually use. This post walks through the entire process from font selection to CI integration.</p>]]></description></item></channel></rss>