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.
What the helper does
Three buttons on the Temp API editor:
- Fix & format — clean up messy/broken JSON and explain what changed
- Generate schema — a JSON Schema (draft 2020-12) from your data
- Generate sample — realistic mock data with the same shape
The design rule: keep AI away from your data
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 };
}
}
Enter fullscreen mode Exit fullscreen mode
The AI is only used for things where being “approximately right” is fine and there’s no source of truth to corrupt:
- explaining what the deterministic repair changed
- generating a schema
- generating brand-new sample data
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 AI calls (Cloudflare Workers AI)
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.
}
Enter fullscreen mode Exit fullscreen mode
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.
The gotcha: response isn’t always a string
Here’s the bug that had me confused for a while. In production:
- Fix & format worked perfectly (including its AI explanation)
- Generate schema and Generate sample both failed with a generic 502
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
Enter fullscreen mode Exit fullscreen mode
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();
}
Enter fullscreen mode Exit fullscreen mode
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:
- “Some calls work, some don’t” is a gift. The difference between the working and broken calls is the bug. Here it was the output type (prose vs JSON), not the model or the binding.
-
A generic
catch → 502hides the answer. One temporary line echoing the real error message turned a guessing game into a one-line fix. (Then I took it back out.)
Keeping it cheap and abuse-resistant
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.
Try it
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. 🛠️
답글 남기기