WebSocket with Claude Code
Learn about websocket using Claude Code. Practical tips and code examples included.
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対策: ユーザー入力のサニタイズ処理
- 再接続ロジック: 切断時の自動再接続とメッセージ再取得
Verwandte Ressourcen
WebSocketの基礎的な実装パターンについてはWebSocket/リアルタイム通信の実装ガイドも参考にしてください。認証周りの実装は認証機能の実装で詳しく解説しています。また、チャットボットとの統合を考えている場合はチャットボット開発もご覧ください。
Socket.IOの公式ドキュメント(socket.io/docs)も併せて確認するとよいでしょう。
Related Posts
So beschleunigen Sie Ihre Nebenprojekte mit Claude Code [Mit Beispielen]
Erfahren Sie, wie Sie persönliche Entwicklungsprojekte mit Claude Code drastisch beschleunigen. Inklusive realer Beispiele und eines praktischen Workflows von der Idee bis zum Deployment.
So automatisieren Sie Refactoring mit Claude Code
Erfahren Sie, wie Sie Code-Refactoring mit Claude Code effizient automatisieren. Inklusive praktischer Prompts und konkreter Refactoring-Muster für reale Projekte.
Vollständiger CORS-Konfigurationsleitfaden mit Claude Code
Erfahren Sie alles über die CORS-Konfiguration mit Claude Code. Mit praktischen Tipps und Codebeispielen.