I run TempTools — a small suite of free, no-signup web tools that expire and delete themselves. The one I use most is Temp API: paste JSON or CSV, get a live mock endpoint in seconds.
I just added an AI helper to it, and the design turned out more interesting than "call an LLM." The rule I set for myself was: AI is never allowed to touch correctness. Here's how that shook out — plus a Cloudflare Workers AI gotcha that broke two of the three features while the third worked fine.
Three buttons on the Temp API editor:
Here's the thing I didn't want: an AI silently rewriting my JSON while pretending to "format" it. If you paste {"id": 42}
and the tool hands back {"id": 43}
, that's not a fix — that's a bug you'll chase for an hour.
So repair and formatting are 100% deterministic. No AI. I use jsonrepair:
export function formatOrRepair(input: string) {
try {
return { ok: true, formatted: JSON.stringify(JSON.parse(input), null, 2), repaired: false };
} catch {
/* not valid — try to repair */
}
try {
const repaired = jsonrepair(input);
return { ok: true, formatted: JSON.stringify(JSON.parse(repaired), null, 2), repaired: true };
} catch {
return { ok: false };
}
}
The AI is only used for things where being "approximately right" is fine and there's no source of truth to corrupt:
That split matters for the copy too. It would be tempting to market this as "AI fixes your JSON!" — but that's not true, and someone will call it out. The UI says the repair runs locally and reserves "AI" for the schema/sample/explanation. Honest and it dodges a whole class of complaints.
The generation runs on Workers AI with an ai
binding — no external API keys, it just runs on the edge:
export const AI_MODEL = "@cf/qwen/qwen2.5-coder-32b-instruct";
async function runText(ai, messages, maxTokens) {
const out = await ai.run(AI_MODEL, { messages, max_tokens: maxTokens, temperature: 0.2 });
return out.response.trim(); // ← this line is a trap. more below.
}
generateSchema
and generateSample
are just runText
with a system prompt that says "output ONLY raw JSON, no markdown fences," and then I strip any stray fences/prose defensively before parsing.
response
isn't always a string Here's the bug that had me confused for a while. In production:
Same model. Same runText
. Same binding. So why did one of three AI calls work and two fail?
I temporarily surfaced the real error in the response and got this:
((intermediate value).response ?? "").trim is not a function
out.response
wasn't a string — so .trim()
didn't exist on it.
The pattern clicked once I saw which calls failed. The explanation prompt returns prose, so response
is a string. The schema and sample prompts return JSON — and when the model's output is JSON, Workers AI can hand you response
as an already-parsed object, not a string. Calling .trim()
on an object throws.
The fix is boring but worth knowing: don't assume response
is a string.
async function runText(ai, messages, maxTokens) {
const out = await ai.run(AI_MODEL, { messages, max_tokens: maxTokens, temperature: 0.2 });
const r = (out as { response?: unknown }).response;
const text = typeof r === "string" ? r : r == null ? "" : JSON.stringify(r);
return text.trim();
}
If response
is a string, use it. If it's an object (parsed JSON), JSON.stringify
it back — which is exactly what I want to hand to the schema/sample path anyway. null
/undefined
becomes an empty string instead of crashing.
Two debugging lessons I keep re-learning:
catch → 502
hides the answer.Because repair/formatting never calls the model, the common case (paste valid-ish JSON, format it) costs zero AI. The model only runs when you ask for an explanation, schema, or sample.
On top of that, AI calls are rate-limited per IP with a tiny rolling log table (same trick I use for uploads), and the input is size-capped before it ever reaches the model. It all stays comfortably inside the Cloudflare free tier.
It's live at ** temptools.webcli.jp/tools/temp-api** — paste some rough JSON and hit the AI buttons. No signup, and the endpoint you create expires on its own.
If you're building on Workers AI, keep that response
-type gotcha in your back pocket. And if you find a rough edge in Temp API, I'd genuinely love to hear it. 🛠️