Você leu a documentação, sabe que o TOON corta as contagens de tokens pela metade em dados tabulares. Agora você quer realmente conectar isso em algo. Este artigo é sobre o encanamento: ler e escrever arquivos .toon, validar TOON em fronteiras de sistema, construir um middleware Express que analisa corpos de requisição TOON, e montar um pipeline banco-de-dados-para-prompt que alimenta TOON diretamente para um LLM. Código real, padrões reais — sem exemplos brinquedo.

Configuração

Instale o pacote do npm. É apenas ESM, então você vai precisar de "type": "module" no seu package.json ou usar a extensão .mjs. Node.js 18+ é tudo que você precisa — sem arquivos de configuração, sem plugins.

bash
npm install @toon-format/toon
js
import { encode, decode } from '@toon-format/toon';

// That's it. encode() → TOON string, decode() → JS value.

Lendo e escrevendo arquivos TOON

O módulo fs do Node.js lida com o I/O. Passe o conteúdo do arquivo diretamente para decode(), ou passe seus dados para encode() e escreva o resultado em disco. Abaixo estão ambos os padrões — síncronos para scripts e ferramentas CLI, assíncronos para rotas de servidor.

js
// --- 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');
js
// --- 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');
}
Sempre use a codificação 'utf8'. Arquivos TOON são texto simples. Omitir o argumento de codificação retorna um Buffer — decode() espera uma string e lançará um erro de tipo se passado um Buffer.

Validando TOON em fronteiras de sistema

decode() lança em entrada inválida, o que é o comportamento certo para um parser mas inconveniente em uma fronteira de API ou consumidor de fila de mensagens onde você precisa de um resultado estruturado, não uma exceção não capturada. A solução é um wrapper fino que transforma o lançamento em um valor de retorno. Este é o padrão que você vai usar em Express route handlers, processadores de fila, e em qualquer outro lugar onde dados externos entram no seu sistema.

js
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 };
  }
}

O uso em uma rota Express ou um consumidor de fila parece idêntico — chame validateToon(), ramifique em valid, e ou prossiga com data ou retorne um 400 / dead-letter a mensagem com a string error. O padrão try/catch mantém o código chamador limpo e previsível.

js
// 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);
});

Construindo um middleware TOON para Express

express.json() analisa corpos application/json e coloca o resultado em req.body. Aqui está a mesma coisa para application/toon. Coloque antes dos seus route handlers e o resto da pilha nunca saberá a diferença.

js
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 });
// });

Convertendo resultados de banco de dados para TOON antes de enviar para LLM

Este é o padrão para o qual o TOON foi construído. Você consulta o banco de dados, recebe de volta um array de linhas, codifica para TOON e coloca direto no seu prompt. O LLM obtém toda a estrutura sem o overhead de repetição de chaves do JSON. Aqui está um pipeline realista usando node-postgres (pg):

js
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);
}

O mesmo padrão funciona para qualquer cliente SQL ou ORM — Prisma, Drizzle, Knex, Sequelize — desde que sua consulta retorne objetos JS simples. encode() pega os nomes das chaves da primeira linha e os usa como cabeçalhos de coluna; linhas subsequentes são escritas como valores separados por vírgulas. Um resultado de 50 linhas que custaria ~1.500 tokens como um array JSON tipicamente custa ~600–700 tokens como TOON.

Lidando com erros e casos extremos

Algumas coisas vale a pena saber antes de você enviar:

  • LLM retorna TOON malformado. Os modelos nem sempre reproduzem um formato perfeitamente, especialmente na primeira tentativa. Envolva decode() em um try/catch (ou use validateToon() acima). Se falhar, registre a resposta bruta, retorne um erro para o chamador, e — se precisar de saída estruturada de forma confiável — adicione uma tentativa de reprocessamento com um prompt de correção explícito: "Sua última resposta não era TOON válido. Por favor, reformate."
  • Valores contendo vírgulas ou dois-pontos. TOON usa vírgulas para separar valores e dois-pontos na sintaxe de objeto — ambos são caracteres significativos. encode() detecta esses automaticamente e envolve o valor afetado em aspas duplas. Você nunca precisa pré-processar seus dados; apenas passe strings brutas.
  • Null e undefined. encode() serializa null como null (puro, sem aspas) e omite propriedades undefined completamente — mesmo comportamento que JSON.stringify(). Ao decodificar, null puro é retornado como JS null.
  • Arrays vazios. encode([]) retorna um array TOON vazio válido. decode() faz o round-trip limpo. Guarde upstream se seu prompt de LLM não deve incluir um dataset vazio.
  • Conjuntos de resultados muito grandes. Não há limite rígido na biblioteca, mas LLMs têm limites de janela de contexto. Pagine ou LIMIT suas consultas antes de codificar — 100–200 linhas é um teto razoável para a maioria dos prompts.
Valide antes de armazenar. Se seu pipeline aceita TOON de uma fonte externa (webhook, fila, cliente de API) e armazena o resultado decodificado em um banco de dados, sempre execute validateToon() primeiro. Deixar um payload malformado chegar à sua camada de banco de dados torna a depuração muito mais difícil do que capturá-lo na fronteira.

Conclusão

Os padrões neste artigo cobrem a maior parte do que você precisa para integrar TOON em uma base de código Node.js real: fs para I/O de arquivo, um wrapper validateToon() para parsing seguro em fronteiras, um middleware Express drop-in para corpos application/toon, e um pipeline DB-para-prompt que transforma linhas SQL em entrada de LLM eficiente em tokens. A biblioteca em si — @toon-format/toon — fica fora do seu caminho: duas funções, sem configuração, lança em entrada inválida. Use TOON Validator para verificar saídas durante o desenvolvimento, TOON Formatter para inspecionar dados codificados, JSON para TOON para converter datasets existentes antes de colá-los em um prompt, e TOON para JSON se precisar passar uma resposta decodificada para um sistema downstream que espera JSON.