Du har läst dokumentationen, du vet att TOON halverar tokenantal på tabelldata. Nu vill du faktiskt koppla ihop det. Den här artikeln handlar om rörmokeri: läsa och skriva .toon-filer, validera TOON vid systemgränser, bygga ett Express-middleware som parsar TOON-begärandekroppar och montera en databas-till-prompt-pipeline som matar TOON direkt till ett LLM. Riktig kod, riktiga mönster — inga leksaksexempel.
Konfiguration
Installera paketet från npm. Det är ESM-only, så du behöver "type": "module" i din package.json eller använda ett .mjs-tillägg. Node.js 18+ är allt du behöver — inga konfigfiler, inga plugins.
npm install @toon-format/toonimport { encode, decode } from '@toon-format/toon';
// That's it. encode() → TOON string, decode() → JS value.Läsa och skriva TOON-filer
Node.js fs-modulen hanterar I/O:t. Skicka filinnehållet direkt till decode(), eller skicka din data till encode() och skriv resultatet till disk. Nedan är båda mönstren — synk för skript och CLI-verktyg, asynk för serverrutter.
// --- Sync (scripts, CLI tools) ---
import { readFileSync, writeFileSync } from 'fs';
import { encode, decode } from '@toon-format/toon';
// Read a .toon file and decode it to a JS value
const raw = readFileSync('./data/products.toon', 'utf8');
const products = decode(raw);
console.log(products); // → JS array or object
// Encode a JS value and write it to a .toon file
const inventory = [
{ sku: 'WDG-001', name: 'Widget A', qty: 142, price: 9.99 },
{ sku: 'WDG-002', name: 'Widget B', qty: 87, price: 14.49 },
{ sku: 'GDG-001', name: 'Gadget X', qty: 31, price: 49.99 },
];
writeFileSync('./data/inventory.toon', encode(inventory, { indent: 2 }), 'utf8');
// --- Async (server routes, pipelines) ---
import { promises as fs } from 'fs';
import { encode, decode } from '@toon-format/toon';
// Read
async function loadReportData(filePath) {
const raw = await fs.readFile(filePath, 'utf8');
return decode(raw); // throws if malformed — handle upstream
}
// Write
async function saveSnapshot(data, filePath) {
const toon = encode(data, { indent: 2 });
await fs.writeFile(filePath, toon, 'utf8');
}'utf8'-kodning. TOON-filer är ren text. Att utelämna kodningsargumentet returnerar en Buffer — decode() förväntar sig en sträng och kastar ett typfel om den skickas en Buffer.Validera TOON vid systemgränser
decode() kastar vid ogiltigt indata, vilket är rätt beteende för en parser men obekvämt vid en API-gräns eller meddelandekö-konsument där du behöver ett strukturerat resultat, inte ett ofångat undantag. Lösningen är en tunn wrapper som omvandlar kastet till ett returvärde. Det här är mönstret du sträcker dig efter i Express-ruthanterare, köprocessorer och var som helst annars extern data går in i ditt system.
import { decode } from '@toon-format/toon';
/**
* Safely parse a TOON string.
* Returns { valid: true, data } on success,
* or { valid: false, error } on failure — never throws.
*/
export function validateToon(input) {
if (typeof input !== 'string') {
return { valid: false, error: 'Input must be a string' };
}
try {
const data = decode(input);
return { valid: true, data };
} catch (err) {
return { valid: false, error: err.message };
}
}
Användning i en Express-rutt eller en kökonsument ser identisk ut — anropa validateToon(), förgrena på valid och antingen fortsätt med data eller returnera en 400 / dead-letter meddelandet med error-strängen. try/catch-mönstret håller anropskoden ren och förutsägbar.
// Example: queue consumer
queue.process('ingest-toon', async (job) => {
const result = validateToon(job.data.payload);
if (!result.valid) {
console.error('Rejecting malformed TOON:', result.error);
return; // dead-letter, skip, or throw depending on your queue
}
await db.insert(result.data);
});
Bygga ett TOON-middleware för Express
express.json() parsar application/json-kroppar och lägger resultatet på req.body. Här är samma sak för application/toon. Lägg in det före dina ruthanterare och resten av stacken märker aldrig skillnaden.
import { decode } from '@toon-format/toon';
/**
* Express middleware: parses application/toon request bodies
* and attaches the decoded value to req.body.
*/
export function toonBodyParser(req, res, next) {
const contentType = req.headers['content-type'] ?? '';
if (!contentType.includes('application/toon')) {
return next(); // not our content type, pass through
}
let body = '';
req.setEncoding('utf8');
req.on('data', (chunk) => { body += chunk; });
req.on('end', () => {
try {
req.body = decode(body);
next();
} catch (err) {
res.status(400).json({ error: 'Invalid TOON body', detail: err.message });
}
});
req.on('error', (err) => {
res.status(500).json({ error: 'Request stream error', detail: err.message });
});
}
// Wire it up:
// app.use(toonBodyParser);
// app.post('/api/import', (req, res) => {
// // req.body is already the decoded JS value
// res.json({ received: Array.isArray(req.body) ? req.body.length : 1 });
// });Konvertera databasresultat till TOON innan sändning till LLM
Det är mönstret TOON byggdes för. Du frågar databasen, får tillbaka en array av rader, kodar till TOON och tappar det direkt i din prompt. LLM:et får all struktur utan JSONs nyckelupprepningsnötfall. Här är en realistisk pipeline med node-postgres (pg):
import pg from 'pg';
import { encode } from '@toon-format/toon';
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
async function buildOrderPrompt(customerId) {
// Step 1: query the database
const { rows } = await pool.query(
`SELECT order_id, created_at, status, total_cents, item_count
FROM orders
WHERE customer_id = $1
ORDER BY created_at DESC
LIMIT 50`,
[customerId]
);
if (rows.length === 0) {
return null;
}
// Step 2: encode rows to TOON
// encode() handles all quoting automatically — no pre-processing needed
const toonData = encode(rows, { indent: 2 });
// Step 3: build the prompt
return [
'Analyse the following order history for a customer support case.',
'Data is in TOON tabular format: name[count]{col1,col2,...}: followed by one row per line.',
'',
toonData,
'',
'Summarise any patterns that suggest the customer has a recurring issue.'
].join('\n');
}
// Calling code:
const prompt = await buildOrderPrompt('cust_8821');
if (prompt) {
const reply = await callLlm(prompt); // your LLM client here
console.log(reply);
}Samma mönster fungerar för vilken SQL-klient eller ORM som helst — Prisma, Drizzle, Knex, Sequelize — så länge din fråga returnerar vanliga JS-objekt. encode() hämtar nyckelnamnen från den första raden och använder dem som kolumnrubriker; efterföljande rader skrivs som kommaseparerade värden. Ett 50-raders resultatset som skulle kosta ~1 500 tokens som en JSON-array kostar typiskt ~600–700 tokens som TOON.
Hantera fel och kantfall
Några saker värda att veta innan du driftsätter:
- LLM returnerar felformaterad TOON. Modeller återger inte alltid ett format perfekt, speciellt vid första försöket. Wrap:a
decode()i ett try/catch (eller användvalidateToon()från ovan). Om det misslyckas, logga råsvaret, returnera ett fel till anroparen och — om du behöver strukturerat utdata tillförlitligt — lägg till ett nytt försök med en explicit korrektionsprompt: "Ditt senaste svar var inte giltig TOON. Formatera om det." - Värden som innehåller kommatecken eller kolon. TOON använder kommatecken för att separera värden och kolon i objektsyntax — båda är viktiga tecken.
encode()detekterar dessa automatiskt och wrapper det berörda värdet med dubbla citationstecken. Du behöver aldrig förbehandla dina data; skicka bara råa strängar. - Null och undefined.
encode()serialiserarnullsomnull(bart, ociterat) och utelämnarundefined-egenskaper helt — samma beteende somJSON.stringify(). Vid avkodning returneras bartnullsom JSnull. - Tomma arrayer.
encode([])returnerar en giltig tom TOON-array.decode()runda-tripar den rent. Vaka uppströms om din LLM-prompt inte bör inkludera ett tomt dataset. - Mycket stora resultatset. Det finns ingen hård gräns i biblioteket, men LLM:er har kontextfönstergränser. Paginera eller
LIMITdina frågor innan kodning — 100–200 rader är ett rimligt tak för de flesta prompter.
validateToon() först. Att låta en felformaterad payload nå ditt DB-lager gör felsökning mycket svårare än att fånga den vid gränsen.Sammanfattning
Mönstren i den här artikeln täcker det mesta av vad du behöver för att integrera TOON i en riktig Node.js-kodbas: fs för fil-I/O, en validateToon()-wrapper för säker gränsparsning, ett drop-in Express-middleware för application/toon-kroppar, och en DB-till-prompt-pipeline som omvandlar SQL-rader till tokeneffektiv LLM-inmatning. Biblioteket självt — @toon-format/toon — håller sig ur vägen: två funktioner, ingen konfiguration, kastar vid ogiltigt indata. Använd TOON Validator för att kontrollera utdata under utveckling, TOON Formatter för att inspektera kodad data, JSON till TOON för att konvertera befintliga dataset innan de klistras in i en prompt, och TOON till JSON om du behöver lämna över ett avkodat svar till ett nedströmssystem som förväntar sig JSON.