Claude CodeでWebSocketチャットアプリを構築する
Claude Codeを活用してリアルタイムWebSocketチャットアプリケーションをゼロから構築する方法を、具体的なコード例とともに解説します。
WebSocketチャットアプリをClaude Codeで作る
リアルタイムチャットアプリはWebSocketの代表的なユースケースです。Claude Codeを使えば、認証付きのチャットルーム、メッセージ履歴、オンラインステータスまで含めた本格的なチャットアプリを効率的に構築できます。
プロジェクトの初期セットアップ
> WebSocketチャットアプリを作りたい。
> Node.js + Express + Socket.IO でサーバーを、
> React + TypeScript でフロントエンドを構築して。
> ルーム機能とメッセージ履歴を実装して。
Claude Codeはこのプロンプトから、サーバーとクライアントの両方を一貫したアーキテクチャで生成してくれます。
サーバーサイドの実装
// server/src/chat-server.ts
import { Server, Socket } from 'socket.io';
import { createServer } from 'http';
import express from 'express';
interface Message {
id: string;
roomId: string;
sender: string;
content: string;
timestamp: number;
}
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: { origin: process.env.CLIENT_URL || 'http://localhost:3000' },
});
// メッセージ履歴をメモリに保持(本番ではDBを使用)
const messageHistory = new Map<string, Message[]>();
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) return next(new Error('認証が必要です'));
// トークン検証ロジック
next();
});
io.on('connection', (socket: Socket) => {
const username = socket.handshake.auth.username;
socket.on('join-room', (roomId: string) => {
socket.join(roomId);
// 過去のメッセージを送信
const history = messageHistory.get(roomId) || [];
socket.emit('message-history', history.slice(-50));
io.to(roomId).emit('user-status', { username, status: 'online' });
});
socket.on('send-message', (data: { roomId: string; content: string }) => {
const message: Message = {
id: crypto.randomUUID(),
roomId: data.roomId,
sender: username,
content: data.content,
timestamp: Date.now(),
};
if (!messageHistory.has(data.roomId)) {
messageHistory.set(data.roomId, []);
}
messageHistory.get(data.roomId)!.push(message);
io.to(data.roomId).emit('new-message', message);
});
socket.on('disconnect', () => {
io.emit('user-status', { username, status: 'offline' });
});
});
httpServer.listen(4000, () => console.log('Chat server running on :4000'));
クライアントサイドの実装
// client/src/hooks/useChat.ts
import { useEffect, useState, useCallback } from 'react';
import { io, Socket } from 'socket.io-client';
interface Message {
id: string;
roomId: string;
sender: string;
content: string;
timestamp: number;
}
export function useChat(roomId: string, token: string, username: string) {
const [messages, setMessages] = useState<Message[]>([]);
const [socket, setSocket] = useState<Socket | null>(null);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
const s = io('http://localhost:4000', {
auth: { token, username },
});
s.on('connect', () => {
setIsConnected(true);
s.emit('join-room', roomId);
});
s.on('message-history', (history: Message[]) => {
setMessages(history);
});
s.on('new-message', (message: Message) => {
setMessages((prev) => [...prev, message]);
});
s.on('disconnect', () => setIsConnected(false));
setSocket(s);
return () => { s.disconnect(); };
}, [roomId, token, username]);
const sendMessage = useCallback((content: string) => {
socket?.emit('send-message', { roomId, content });
}, [socket, roomId]);
return { messages, sendMessage, isConnected };
}
メッセージコンポーネント
// client/src/components/ChatRoom.tsx
import { useChat } from '../hooks/useChat';
import { useState } from 'react';
export function ChatRoom({ roomId, token, username }: {
roomId: string;
token: string;
username: string;
}) {
const { messages, sendMessage, isConnected } = useChat(roomId, token, username);
const [input, setInput] = useState('');
const handleSend = () => {
if (!input.trim()) return;
sendMessage(input);
setInput('');
};
return (
<div className="flex flex-col h-screen">
<div className="p-4 border-b flex justify-between">
<h2>Room: {roomId}</h2>
<span className={isConnected ? 'text-green-500' : 'text-red-500'}>
{isConnected ? '接続中' : '切断'}
</span>
</div>
<div className="flex-1 overflow-y-auto p-4 space-y-2">
{messages.map((msg) => (
<div key={msg.id} className={msg.sender === username ? 'text-right' : ''}>
<span className="text-sm text-gray-500">{msg.sender}</span>
<p className="bg-gray-100 rounded-lg p-2 inline-block">{msg.content}</p>
</div>
))}
</div>
<div className="p-4 border-t flex gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
className="flex-1 border rounded px-3 py-2"
placeholder="メッセージを入力..."
/>
<button onClick={handleSend} className="bg-blue-500 text-white px-4 rounded">
送信
</button>
</div>
</div>
);
}
本番環境での注意点
Claude Codeに以下の点を追加で依頼すると、本番品質に近づけられます。
- メッセージの永続化: RedisやPostgreSQLにメッセージを保存する
- レート制限: スパム防止のためのメッセージ送信制限
- XSS対策: ユーザー入力のサニタイズ処理
- 再接続ロジック: 切断時の自動再接続とメッセージ再取得
関連リソース
WebSocketの基礎的な実装パターンについてはWebSocket/リアルタイム通信の実装ガイドも参考にしてください。認証周りの実装は認証機能の実装で詳しく解説しています。また、チャットボットとの統合を考えている場合はチャットボット開発もご覧ください。
Socket.IOの公式ドキュメント(socket.io/docs)も併せて確認するとよいでしょう。
#Claude Code
#WebSocket
#チャット
#リアルタイム
#Node.js
関連記事
Use Cases
Use Cases
Claude CodeでCORS設定完全ガイド:クロスオリジン通信の実践解説
Claude Codeを活用したCORS設定の完全ガイド。プリフライトリクエスト、認証付きリクエスト、トラブルシューティングまで実践的に解説します。
Use Cases
Use Cases
Claude Codeで通貨フォーマットを正しく実装する
Claude Codeを使って、多通貨対応・ロケール別フォーマット・為替レート変換など、通貨の表示と処理を正しく実装する方法を解説します。
Use Cases
Use Cases
Claude CodeでDiscord Botを開発する実践ガイド
Claude Codeを活用したDiscord Botの開発方法を解説。discord.js、スラッシュコマンド、ボタン操作、Embed、音声チャンネル連携まで実践的に紹介します。