Du har lest dokumentasjonen, du vet at TOON halverer tokenantall på tabelldata. Nå vil du faktisk koble det inn i noe. Denne artikkelen handler om rørleggingen: lesing og skriving av .toon-filer, validering av TOON ved systemgrenser, bygging av en Express-mellomvare som parser TOON-forespørselskropper, og samling av en database-til-prompt-pipeline som sender TOON direkte til en LLM. Ekte kode, ekte mønstre — ingen leketøyseksempler.
Oppsett
Installer pakken fra npm. Den er ESM-only, så du trenger "type": "module" i package.json eller bruk en .mjs-utvidelse. Node.js 18+ er alt du trenger — ingen konfigurasjonsfiler, ingen plugins.
npm install @toon-format/toonimport { encode, decode } from '@toon-format/toon';
// That's it. encode() → TOON string, decode() → JS value.Lesing og skriving av TOON-filer
Node.js' fs-modul håndterer I/O. Send filinnholdet direkte inn i decode(), eller send dataene dine til encode() og skriv resultatet til disk. Nedenfor er begge mønstre — synkront for skript og CLI-verktøy, asynkront for serverruter.
// --- 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'-koding. TOON-filer er ren tekst. Å utelate kodingsargumentet returnerer en Buffer — decode() forventer en streng og vil kaste en typefeil hvis den mottar en Buffer.Validering av TOON ved systemgrenser
decode() kaster ved ugyldig inndata, som er riktig oppførsel for en parser men upraktisk ved en API-grense eller message-queue-forbruker der du trenger et strukturert resultat, ikke et ufanget unntak. Løsningen er en tynn innpakning som gjør kastet om til en returverdi. Dette er mønsteret du vil gripe etter i Express-rutebehandlere, kø-behandlere og overalt ellers der eksterne data kommer inn i systemet ditt.
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 };
}
}
Bruk i en Express-rute eller en kø-forbruker ser identisk ut — kall validateToon(), forgren på valid, og fortsett enten med data eller returner 400 / dead-letter meldingen med error-strengen. Mønsteret try/catch holder den kallende koden ren og forutsigbar.
// 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);
});
Bygge en TOON-mellomvare for Express
express.json() parser application/json-kropper og setter resultatet på req.body. Her er det samme for application/toon. Sett det inn før rutebehandlerne dine og resten av stacken merker aldri forskjellen.
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 });
// });Konvertering av databaseresultater til TOON før sending til LLM
Dette er mønsteret TOON ble bygget for. Du spør databasen, får tilbake et array av rader, koder til TOON og setter det rett inn i prompten din. LLM-en får all strukturen uten noen av JSONs nøkkelgjentakelses-overhead. Her er en realistisk pipeline som bruker 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);
}Det samme mønsteret fungerer for enhver SQL-klient eller ORM — Prisma, Drizzle, Knex, Sequelize — så lenge spørringen din returnerer vanlige JS-objekter. encode() henter nøkkelnavnene fra den første raden og bruker dem som kolonneoverskrifter; påfølgende rader skrives som kommaseparerte verdier. Et 50-raders resultatsett som ville koste ~1 500 tokens som et JSON-array koster typisk ~600–700 tokens som TOON.
Håndtering av feil og edge cases
Noen ting er verdt å vite før du sender kode til produksjon:
- LLM returnerer misformet TOON. Modeller reproduserer ikke alltid et format perfekt, spesielt ikke ved første forsøk. Omgir
decode()i en try/catch (eller brukvalidateToon()fra ovenfor). Hvis det feiler, logg det rå svaret, returner en feil til kallende kode, og — hvis du trenger strukturert utdata pålitelig — legg til et nytt forsøk med en eksplisitt korreksjons-prompt: "Ditt siste svar var ikke gyldig TOON. Formater det på nytt." - Verdier som inneholder kommaer eller kolon. TOON bruker kommaer til å skille verdier og kolon i objektsyntaks — begge er betydningsfulle tegn.
encode()oppdager disse automatisk og omgir den berørte verdien med doble anførselstegn. Du trenger aldri å forbehandle dataene; send bare rå strenger. - Null og undefined.
encode()serialiserernullsomnull(bart, uten anførselstegn) og utelaterundefined-egenskaper fullstendig — samme oppførsel somJSON.stringify(). Ved dekoding returneres bartnullsom JSnull. - Tomme arrays.
encode([])returnerer et gyldig tomt TOON-array.decode()round-tripper det rent. Vakt oppstrøms hvis LLM-prompten din ikke bør inkludere et tomt datasett. - Veldig store resultatsett. Det er ingen hard grense i biblioteket, men LLM-er har kontekstvinduegrenser. Paginer eller
LIMITspørringene dine før koding — 100–200 rader er et rimelig tak for de fleste prompter.
validateToon() først. Å la en misformet payload nå DB-laget ditt gjør feilsøking mye vanskeligere enn å fange det ved grensen.Oppsummering
Mønstrene i denne artikkelen dekker det meste av hva du trenger for å integrere TOON i en ekte Node.js-kodebase: fs for fil-I/O, en validateToon()-innpakning for sikker grense-parsing, en drop-in Express-mellomvare for application/toon-kropper, og en DB-til-prompt-pipeline som gjør SQL-rader om til tokeneffektivt LLM-inndata. Biblioteket selv — @toon-format/toon — holder seg ute av veien: to funksjoner, ingen konfigurasjon, kaster ved ugyldig inndata. Bruk TOON Validator for å sjekke utdata under utvikling, TOON Formatter for å inspisere kodet data, JSON til TOON for å konvertere eksisterende datasett før du setter dem inn i en prompt, og TOON til JSON hvis du må overlevere et dekodet svar til et nedstrøms system som forventer JSON.