문서를 읽었고, TOON이 표 형식 데이터에서 토큰 수를 절반으로 줄인다는 것을 알고 있습니다. 이제 실제로 연결하고 싶습니다. 이 문서는 배관에 관한 것입니다: .toon 파일 읽고 쓰기, 시스템 경계에서 TOON 검증, TOON 요청 본문을 파싱하는 Express 미들웨어 구축, TOON을 LLM에 직접 피드하는 데이터베이스-에서-프롬프트 파이프라인 조립. 실제 코드, 실제 패턴 — 장난감 예시 없음.

설정

npm에서 패키지를 설치하세요. ESM 전용이므로 package.json"type": "module"이 있거나 .mjs 확장자를 사용해야 합니다. Node.js 18+이 필요한 전부입니다 — 설정 파일 없음, 플러그인 없음.

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

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

TOON 파일 읽고 쓰기

Node.js fs 모듈이 I/O를 처리합니다. 파일 내용을 decode()에 직접 전달하거나, 데이터를 encode()에 전달하고 결과를 디스크에 씁니다. 아래는 두 패턴 모두입니다 — 스크립트와 CLI 도구에는 동기적, 서버 라우트에는 비동기적.

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');
}
항상 'utf8' 인코딩을 사용하세요. TOON 파일은 일반 텍스트입니다. 인코딩 인수를 생략하면 Buffer가 반환됩니다 — decode()는 문자열을 기대하며 Buffer가 전달되면 타입 오류를 발생시킵니다.

시스템 경계에서 TOON 검증

decode()는 유효하지 않은 입력에서 예외를 발생시킵니다, 이는 파서에게 올바른 동작이지만 구조화된 결과가 필요한 API 경계나 메시지 큐 소비자에서는 불편합니다 — 잡히지 않은 예외가 아닌. 해결책은 발생을 반환 값으로 전환하는 얇은 래퍼입니다. Express 라우트 핸들러, 큐 프로세서, 외부 데이터가 시스템에 들어오는 어느 곳에서나 사용하는 패턴입니다.

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

Express 라우트나 큐 소비자에서의 사용은 동일합니다 — validateToon()을 호출하고, valid로 분기하며, data로 진행하거나 error 문자열과 함께 400을 반환하거나 메시지를 dead-letter 처리합니다. try/catch 패턴은 호출 코드를 깨끗하고 예측 가능하게 유지합니다.

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

Express를 위한 TOON 미들웨어 구축

express.json()application/json 본문을 파싱하고 결과를 req.body에 넣습니다. 다음은 application/toon에 대한 동일한 것입니다. 라우트 핸들러 앞에 넣으면 스택의 나머지 부분은 차이를 알 수 없습니다.

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

LLM에 보내기 전에 데이터베이스 결과를 TOON으로 변환

이것이 TOON이 구축된 패턴입니다. 데이터베이스를 쿼리하고, 행 배열을 돌려받고, TOON으로 인코딩하고, 프롬프트에 직접 넣습니다. LLM은 JSON의 키 반복 오버헤드 없이 모든 구조를 얻습니다. 다음은 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);
}

동일한 패턴은 모든 SQL 클라이언트나 ORM에 작동합니다 — Prisma, Drizzle, Knex, Sequelize — 쿼리가 일반 JS 객체를 반환하는 한. encode()는 첫 번째 행에서 키 이름을 가져와 열 헤더로 사용합니다; 후속 행은 쉼표로 구분된 값으로 작성됩니다. JSON 배열로 약 ~1,500 토큰이 드는 50행 결과 집합은 TOON으로 일반적으로 ~600~700 토큰이 듭니다.

오류 및 엣지 케이스 처리

배포 전에 알아두어야 할 몇 가지 사항들:

  • LLM이 잘못된 TOON을 반환합니다. 모델이 항상 형식을 완벽하게 재현하지는 않으며, 특히 첫 번째 시도에서. decode()를 try/catch로 감싸거나(또는 위의 validateToon() 사용). 실패하면 원시 응답을 기록하고 호출자에게 오류를 반환하고 — 구조화된 출력이 안정적으로 필요한 경우 — 명시적인 수정 프롬프트로 재시도를 추가하세요: "마지막 응답이 유효한 TOON이 아니었습니다. 다시 형식을 맞춰주세요."
  • 쉼표나 콜론이 포함된 값. TOON은 쉼표를 사용하여 값을 구분하고 콜론을 객체 구문에 사용합니다 — 둘 다 의미 있는 문자입니다. encode()가 이것을 자동으로 감지하고 영향 받는 값을 이중 따옴표로 묶습니다. 데이터를 사전 처리할 필요가 없습니다; 원시 문자열을 그냥 전달하세요.
  • Null과 undefined. encode()nullnull(베어, 따옴표 없음)로 직렬화하고 undefined 속성은 완전히 생략합니다 — JSON.stringify()와 동일한 동작. 디코딩 시, 베어 null은 JS null로 반환됩니다.
  • 빈 배열. encode([])는 유효한 빈 TOON 배열을 반환합니다. decode()는 깔끔하게 반환합니다. LLM 프롬프트에 빈 데이터셋이 포함되지 않아야 하는 경우 업스트림에서 보호하세요.
  • 매우 큰 결과 집합. 라이브러리에 하드 제한이 없지만, LLM에는 컨텍스트 창 제한이 있습니다. 인코딩 전에 쿼리를 페이지네이션하거나 LIMIT을 적용하세요 — 대부분의 프롬프트에는 100~200행이 합리적인 상한선입니다.
저장 전에 검증하세요. 파이프라인이 외부 소스에서 TOON을 수락하고 (웹훅, 큐, API 클라이언트) 디코딩된 결과를 데이터베이스에 저장하는 경우, 항상 먼저 validateToon()을 실행하세요. 잘못된 페이로드가 DB 레이어에 도달하게 허용하면 경계에서 잡는 것보다 디버깅이 훨씬 어려워집니다.

마무리

이 문서의 패턴들은 실제 Node.js 코드베이스에 TOON을 통합하는 데 필요한 대부분을 커버합니다: 파일 I/O를 위한 fs, 안전한 경계 파싱을 위한 validateToon() 래퍼, application/toon 본문을 위한 드롭인 Express 미들웨어, SQL 행을 토큰 효율적인 LLM 입력으로 변환하는 DB-에서-프롬프트 파이프라인. 라이브러리 자체 — @toon-format/toon — 는 방해가 되지 않습니다: 두 가지 함수, 설정 없음, 유효하지 않은 입력에서 예외 발생. 개발 중 출력을 확인하려면 TOON Validator를 사용하고, 인코딩된 데이터를 검사하려면 TOON Formatter를, LLM에 붙여넣기 전에 기존 데이터셋을 변환하려면 JSON to TOON을, 디코딩된 응답을 JSON을 기대하는 다운스트림 시스템에 넘겨줘야 할 때는 TOON to JSON을 사용하세요.