Chat WebSocket avec Claude Code
Découvrez chat WebSocket avec Claude Code. Conseils pratiques et exemples de code inclus.
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="Type a message..."
/>
<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)も併せて確認するとよいでしょう。
Related Posts
Comment booster vos projets personnels avec Claude Code [Avec exemples]
Apprenez à accélérer considérablement vos projets de développement personnels avec Claude Code. Inclut des exemples concrets et un workflow pratique de l'idée au déploiement.
Comment automatiser le refactoring avec Claude Code
Apprenez à automatiser efficacement le refactoring de code avec Claude Code. Inclut des prompts pratiques et des patterns de refactoring concrets pour des projets réels.
Guide complet de configuration CORS avec Claude Code
Découvrez le guide complet de configuration CORS avec Claude Code. Conseils pratiques et exemples de code inclus.