How to Implement WebSocket/Real-Time Communication with Claude Code
Learn how to implement websocket/real-time communication using Claude Code. Includes practical code examples and step-by-step guidance.
リアルタイム通信開発でClaude Codeを活用する
チャット、通知、共同Editなど、リアルタイム通信が必要なアプリケーションは増えています。Claude Codeはサーバーサイドとクライアントサイドの両方を理解した上で、一貫した実装を支援します。
Socket.IOによるチャット機能の実装
> Socket.IOを使ったリアルタイムチャットのサーバーを作成して。
> ルーム機能、タイピングインジケーター、既読機能を実装して。
サーバーサイド
import express from 'express';
import { createServer } from 'http';
import { Server, Socket } from 'socket.io';
const app = express();
const server = createServer(app);
const io = new Server(server, {
cors: { origin: 'http://localhost:5173' },
});
interface ChatMessage {
id: string;
roomId: string;
userId: string;
content: string;
timestamp: Date;
}
const rooms = new Map<string, Set<string>>();
io.on('connection', (socket: Socket) => {
const userId = socket.handshake.auth.userId;
console.log(`User connected: ${userId}`);
socket.on('join-room', (roomId: string) => {
socket.join(roomId);
if (!rooms.has(roomId)) rooms.set(roomId, new Set());
rooms.get(roomId)!.add(userId);
socket.to(roomId).emit('user-joined', {
userId,
members: Array.from(rooms.get(roomId)!),
});
});
socket.on('send-message', async (data: { roomId: string; content: string }) => {
const message: ChatMessage = {
id: crypto.randomUUID(),
roomId: data.roomId,
userId,
content: data.content,
timestamp: new Date(),
};
// Save to DB
await saveMessage(message);
io.to(data.roomId).emit('new-message', message);
});
socket.on('typing-start', (roomId: string) => {
socket.to(roomId).emit('user-typing', { userId, isTyping: true });
});
socket.on('typing-stop', (roomId: string) => {
socket.to(roomId).emit('user-typing', { userId, isTyping: false });
});
socket.on('mark-read', (data: { roomId: string; messageId: string }) => {
socket.to(data.roomId).emit('message-read', {
userId,
messageId: data.messageId,
});
});
socket.on('disconnect', () => {
rooms.forEach((members, roomId) => {
if (members.delete(userId)) {
io.to(roomId).emit('user-left', { userId });
}
});
});
});
server.listen(3000, () => console.log('Server running on port 3000'));
クライアントサイド(React)
import { useEffect, useState, useCallback } from 'react';
import { io, Socket } from 'socket.io-client';
let socket: Socket;
export function useChat(roomId: string, userId: string) {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [typingUsers, setTypingUsers] = useState<Set<string>>(new Set());
useEffect(() => {
socket = io('http://localhost:3000', { auth: { userId } });
socket.emit('join-room', roomId);
socket.on('new-message', (message: ChatMessage) => {
setMessages(prev => [...prev, message]);
});
socket.on('user-typing', ({ userId: uid, isTyping }) => {
setTypingUsers(prev => {
const next = new Set(prev);
isTyping ? next.add(uid) : next.delete(uid);
return next;
});
});
return () => { socket.disconnect(); };
}, [roomId, userId]);
const sendMessage = useCallback((content: string) => {
socket.emit('send-message', { roomId, content });
}, [roomId]);
const startTyping = useCallback(() => {
socket.emit('typing-start', roomId);
}, [roomId]);
const stopTyping = useCallback(() => {
socket.emit('typing-stop', roomId);
}, [roomId]);
return { messages, typingUsers, sendMessage, startTyping, stopTyping };
}
Server-Sent Events(SSE)による通知
WebSocketほどの双方向性が不要な場合、SSEが軽量な選択肢です。
// server
app.get('/api/notifications/stream', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
const userId = req.query.userId as string;
const sendEvent = (data: object) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
// 新しい通知があれば送信
const unsubscribe = notificationBus.subscribe(userId, sendEvent);
req.on('close', () => {
unsubscribe();
res.end();
});
});
// client
function useNotifications(userId: string) {
const [notifications, setNotifications] = useState<Notification[]>([]);
useEffect(() => {
const eventSource = new EventSource(
`/api/notifications/stream?userId=${userId}`
);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
setNotifications(prev => [data, ...prev]);
};
return () => eventSource.close();
}, [userId]);
return notifications;
}
接続の安定性を高める
本番環境では、再接続ロジックやハートビートの実装が重要です。
const socket = io('http://localhost:3000', {
auth: { userId },
reconnection: true,
reconnectionAttempts: 10,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
timeout: 20000,
});
socket.on('connect_error', (err) => {
console.error('Connection error:', err.message);
});
socket.on('reconnect', (attempt) => {
console.log(`Reconnected after ${attempt} attempts`);
// Reconnect後にルームに再参加
socket.emit('join-room', currentRoomId);
});
Zusammenfassung
Claude Codeを活用すれば、WebSocketやSSEを使ったリアルタイム通信機能をサーバー・クライアント両方一貫して実装できます。プロンプトの書き方次第でコードの質が大きく変わるため、プロンプトテクニックを身につけておくことが重要です。個人開発でチャット機能を実装する際は個人開発を爆速にする方法も参考にしてください。
詳しくはAnthropic公式ドキュメントやSocket.IO公式ドキュメントをご覧ください。
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.