慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Y
Y Combinator Blog
Blog — PlanetScale
Blog — PlanetScale
H
Hackread – Cybersecurity News, Data Breaches, AI and More
WordPress大学
WordPress大学
B
Blog RSS Feed
A
About on SuperTechFans
V
Visual Studio Blog
J
Java Code Geeks
U
Unit 42
人人都是产品经理
人人都是产品经理
Martin Fowler
Martin Fowler
Recent Announcements
Recent Announcements
M
MIT News - Artificial intelligence
IT之家
IT之家
The Cloudflare Blog
T
The Blog of Author Tim Ferriss
C
Check Point Blog
博客园 - 叶小钗
P
Proofpoint News Feed
Microsoft Security Blog
Microsoft Security Blog
B
Blog
S
SegmentFault 最新的问题
Microsoft Azure Blog
Microsoft Azure Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How I turned a Python function into a web app in one deco...
Kajetan Tuke · 2026-05-24 · via DEV Community

I've been building small utility tools for the web; JSON formatters, CSV processors, PDF text extractors, those kinds of things. The kind of tools where you have a problem, write a 50-line Python function to solve it, and it just works. Then, you want to share it with someone, but they can't be bothered (or don't know how) to set up the script and run it locally.

The obvious solution is "build a web app". The obvious problem is that building a frontend for every small script is a lot of overhead for something that should take an afternoon.

So I built something a little different.

The architecture

TL;DR: a Python function decorated with @tool() automatically becomes a web app. No React. No API endpoint. No routing.

Here's what a tool looks like on the Python side:

from nix_sdk import tool, TextResult

@tool(
    name="Simple JSON tool",
    description="Validate a JSON file - paste or upload!",
    slug="json-tool"
)
def json_formatter(
    json_input: str = Input(label="JSON input", placeholder="Paste JSON here..."),
    indent: int = Dropdown(label="Indent width", choices=[2, 4, 8], default=2),
    sort_keys: bool = Switch(label="Sort keys alphabetically"),
) -> TextResult:
    """Format and validate a JSON document."""
    import json
    parsed = json.loads(json_input)
    return TextResult(value=json.dumps(parsed, indent=indent, sort_keys=sort_keys))

Enter fullscreen mode Exit fullscreen mode

The @tool() decorator inspects the function's type hints and default values, and auto-generates a JSON Schema manifest. That manifest looks something like this:

{
"name": "Simple JSON tool",
"slug": "json-tool",
"input_schema": {
"type": "object",
"properties": {
"json_input": {
"type": "string",
"x-nix": { "widget": "textarea", "label": "JSON input" }
},
"indent": {
"type": "integer",
"enum": [2, 4, 8],
"x-nix": { "widget": "dropdown", "label": "Indent width" }
},
"sort_keys": {
"type": "boolean",
"x-nix": { "widget": "switch", "label": "Sort keys alphabetically" }
}
}
},
"output": { "type": "text" }
}

Separately, the Nix frontend shell reads that manifest and renders the form. Completely automatically.

What the shell does

The Next.js frontend has one dynamic route: /tools/[slug]. It fetches the manifest for that slug from the FastAPI backend, then renders the form using a custom renderer registry. Each x-nix.widget type maps to a Mantine component — textarea becomes a Textarea, dropdown becomes a Select, switch becomes a Switch, file becomes a file upload zone.

The same shell also renders a static landing page at /tools/[slug] with optional seo fields for metadata, H1, and FAQ content so that the content can be posted publicly. One Python file produces both the tool interface and the SEO-optimised landing page.

No React by you. No routing by you. No API wiring by you.

How execution works

The frontend submits the form to POST /api/tools/{slug}/run. FastAPI looks up the tool by slug, validates the input against the JSON Schema, and calls the Python function in a thread via asyncio.to_thread().

For long-running tools, there's a WebSocket path at /ws/tools/{slug}/run. The tool can call progress("Step 2 of 4: processing rows...") from inside the function and those messages stream to the UI in real time.

File uploads are handled as multipart form data. Files are ephemeral - held in temp storage during execution, then discarded. Nothing is persisted.

What's live now

I've used this to build nine tools that are live at nix.tech:

  • JSON Formatter & Validator and XML Formatter & Validator; validates with exact line/column error locations, finds all issues at once rather than stopping at the first
  • PDF Text Extractor; page-range selection, explicit scanned-PDF detection
  • CSV to JSON Converter; handles TSV too
  • CSV Deduplicator; column-level dedup with keep-first/keep-last options
  • Markdown to HTML; GFM extensions, fragment or full page output
  • Base64 Encoder/Decoder; handles files, not just strings
  • SEO Keyword Research; uses DataForSEO's API (to see how it works in these tools!) and provides search volume, CPC and ad competition without a Google Ads account
  • Alt Text Generator; AI-generated, SEO-focused alt text with optional site context

All the tools have free usage limits, without sign-ups. Files discarded after processing.

Tradeoffs

The manifest-driven approach has obvious limits. Complex multi-step flows are hard to express in a flat JSON Schema. Conditional field visibility requires extensions to the spec. Rich output types (e.g., interactive charts, side-by-side diffs) need custom renderer work.

For single-function utility tools - which is where I was testing for now — none of those limits are an issue. The upside is that adding a new tool is adding one Python file. The frontend, API endpoint, landing page, and form all derive from the manifest automatically.

Whether that tradeoff stays favourable at scale is a different question.

If any of the architecture is interesting to dig into further, happy to go into more detail in the comments!