← Node.js言語ページに戻る
🟢

Node.js言語 サンプルコード

文法解説で学んだ内容を組み合わせた、実践的なサンプルプログラムを3本紹介します。難易度が上がる順に、①簡易TODO APIサーバー、②非同期ファイル読み書きを使った家計簿ツール、③ストリームとイベントを使ったログ集計ツールを扱います。

サンプル1:簡易TODO APIサーバー(httpモジュール)

組み込みのhttpモジュールだけで、メモリ上のデータを操作するシンプルなREST風APIを作ります。req.urlreq.methodで手動ルーティングし、POSTのリクエストボディはストリームのdata / endイベントで少しずつ受け取って組み立てます。JSONのパースやレスポンスの組み立てでtry/catchによるエラーハンドリングも行っています。

SAMPLE PROGRAM
const http = require("http");

let todos = [
  { id: 1, title: "牛乳を買う", done: false },
  { id: 2, title: "Node.jsの復習", done: false },
];
let nextId = 3;

function sendJson(res, statusCode, data) {
  const body = JSON.stringify(data);
  res.writeHead(statusCode, { "Content-Type": "application/json; charset=utf-8" });
  res.end(body);
}

// POSTのリクエストボディをストリームで受け取って文字列に組み立てる
function readBody(req) {
  return new Promise((resolve, reject) => {
    let raw = "";
    req.on("data", (chunk) => {
      raw += chunk; // チャンクを少しずつ受信
    });
    req.on("end", () => resolve(raw));
    req.on("error", reject);
  });
}

const server = http.createServer(async (req, res) => {
  try {
    if (req.method === "GET" && req.url === "/todos") {
      return sendJson(res, 200, todos);
    }

    if (req.method === "POST" && req.url === "/todos") {
      const raw = await readBody(req);
      const input = JSON.parse(raw); // 不正なJSONならcatchへ
      const todo = { id: nextId++, title: input.title, done: false };
      todos.push(todo);
      return sendJson(res, 201, todo);
    }

    sendJson(res, 404, { error: "Not Found" });
  } catch (err) {
    sendJson(res, 400, { error: "リクエストの処理に失敗しました: " + err.message });
  }
});

server.listen(3000, () => {
  console.log("http://localhost:3000/todos で待ち受け中");
});

サンプル2:非同期ファイル読み書きを使う家計簿ツール

fs/promisesasync/awaitを使い、JSONファイルに保存された家計簿データを読み書きします。ファイルがまだ存在しない場合のエラー(err.code === "ENOENT")を判別して初期データを作るなど、実務でもよくあるエラーハンドリングのパターンを含んでいます。

SAMPLE PROGRAM
const fs = require("fs/promises");

const FILE_PATH = "./ledger.json";

async function loadLedger() {
  try {
    const raw = await fs.readFile(FILE_PATH, "utf-8");
    return JSON.parse(raw);
  } catch (err) {
    if (err.code === "ENOENT") {
      // ファイルがまだない場合は空のデータから開始
      return { entries: [] };
    }
    throw err; // それ以外のエラーは呼び出し元に伝える
  }
}

async function saveLedger(ledger) {
  const json = JSON.stringify(ledger, null, 2);
  await fs.writeFile(FILE_PATH, json, "utf-8");
}

async function addEntry(title, amount) {
  const ledger = await loadLedger();
  ledger.entries.push({ title, amount, date: new Date().toISOString() });
  await saveLedger(ledger);
  return ledger;
}

function summarize(ledger) {
  return ledger.entries.reduce((total, e) => total + e.amount, 0);
}

(async () => {
  try {
    await addEntry("ランチ", -800);
    await addEntry("給料", 250000);
    const ledger = await loadLedger();
    console.log("収支合計:", summarize(ledger), "円");
  } catch (err) {
    console.error("家計簿の処理でエラーが発生しました:", err.message);
  }
})();

サンプル3:ストリームとEventEmitterを使うログ集計ツール

大きなログファイルを一度に全部メモリへ読み込まず、readlinecreateReadStreamを組み合わせて1行ずつ処理します。自作のEventEmitterを使って「一定件数ごとの進捗」「完了」「エラー」を通知するイベント駆動の設計にしており、呼び出し側はon()でイベントを購読するだけで進捗を受け取れます。

SAMPLE PROGRAM
const fs = require("fs");
const readline = require("readline");
const { EventEmitter } = require("events");

class LogAnalyzer extends EventEmitter {
  constructor(keyword) {
    super();
    this.keyword = keyword;
  }

  analyze(filePath) {
    let lineCount = 0;
    let matchCount = 0;

    const stream = fs.createReadStream(filePath, { encoding: "utf-8" });
    stream.on("error", (err) => this.emit("error", err));

    const rl = readline.createInterface({ input: stream });

    rl.on("line", (line) => {
      lineCount++;
      if (line.includes(this.keyword)) {
        matchCount++;
      }
      if (lineCount % 1000 === 0) {
        this.emit("progress", { lineCount, matchCount });
      }
    });

    rl.on("close", () => {
      this.emit("done", { lineCount, matchCount });
    });
  }
}

const analyzer = new LogAnalyzer("ERROR");

analyzer.on("progress", ({ lineCount, matchCount }) => {
  console.log(`進捗: ${lineCount}行処理 / ${matchCount}件ヒット`);
});

analyzer.on("done", ({ lineCount, matchCount }) => {
  console.log(`完了: 全${lineCount}行中、${matchCount}件が"ERROR"を含んでいました`);
});

analyzer.on("error", (err) => {
  console.error("ログ解析中にエラーが発生しました:", err.message);
});

analyzer.analyze("app.log");

理解度チェッククイズに挑戦する →