💬 チャットサービス
チャットサービスは、リアルタイムメッセージング、チャンネル管理、およびファイル共有を含むチャット機能のための完全なREST APIを提供します。Nodeblocks関数コンポジションアプローチを使用して構築され、MongoDBとシームレスに統合されます。
🚀 クイックスタート
import express from 'express';
import { MongoClient } from 'mongodb';
import { middlewares, services } from '@nodeblocks/backend-sdk';
const { nodeBlocksErrorMiddleware } = middlewares;
const { chatService } = services;
const client = new MongoClient('mongodb://localhost:27017').db('dev');
express()
.use(
chatService(
{
channels: client.collection('channels'),
messages: client.collection('messages'),
identity: client.collection('identity'),
},
{
authSecrets: {
authEncSecret: 'your-encryption-secret',
authSignSecret: 'your-signing-secret',
},
user: {
typeIds: {
admin: '100',
guest: '000',
user: '001',
},
},
chat: {
maxMessageLength: 2000,
allowFileSharing: true,
maxFileSize: 10 * 1024 * 1024, // 10MB
},
}
)
)
.use(nodeBlocksErrorMiddleware())
.listen(8089, () => console.log('チャットサービスが起動しました'));
📋 エンドポイント概要
メソッド | パス | 説明 | 認証 |
---|---|---|---|
POST | /channels | 新規チャンネルを作成 | Bearerトークン必須 |
GET | /channels/:channelId | IDでチャンネルを取得 | Bearerトークン必須(メンバー) |
GET | /channels | チャンネルリストを取得 | Bearerトークン必須 |
PATCH | /channels/:channelId | チャンネルを更新 | Bearerトークン必須(管理者) |
DELETE | /channels/:channelId | チャンネルを削除 | Bearerトークン必須(作成者/管理者) |
POST | /channels/:channelId/messages | メッセージを送信 | Bearerトークン必須(メンバー) |
GET | /channels/:channelId/messages | メッセージ履歴を取得 | Bearerトークン必須(メンバー) |
PATCH | /messages/:messageId | メッセージを編集 | Bearerトークン必須(作成者) |
DELETE | /messages/:messageId | メッセージを削除 | Bearerトークン必須(作成者/管理者) |
💬 チャット操作
1. チャンネル作成
curl -X POST http://localhost:8089/channels \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "プロジェクト議論",
"description": "新プロジェクトに関する議論チャンネル",
"type": "public",
"members": [
"user-1-uuid",
"user-2-uuid"
],
"settings": {
"allowFileSharing": true,
"allowReactions": true,
"messageHistory": true
}
}'
レスポンス:
{
"channelId": "channel-uuid-here",
"message": "チャンネルが正常に作成されました"
}
2. メッセージ送信
# テキストメッセージ
curl -X POST http://localhost:8089/channels/channel-uuid-here/messages \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "こんにちは皆さん!新しいプロジェクトについて話し合いましょう。",
"type": "text"
}'
# ファイル付きメッセージ
curl -X POST http://localhost:8089/channels/channel-uuid-here/messages \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "プロジェクト仕様書を添付しました。",
"type": "file",
"attachments": [
{
"filename": "project-spec.pdf",
"url": "https://storage.example.com/files/project-spec.pdf",
"size": 1024000,
"mimeType": "application/pdf"
}
]
}'
# リプライメッセージ
curl -X POST http://localhost:8089/channels/channel-uuid-here/messages \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "良いアイデアですね!",
"type": "text",
"replyTo": "parent-message-uuid"
}'
3. メッセージ履歴取得
# 最新メッセージ取得
curl -X GET "http://localhost:8089/channels/channel-uuid-here/messages?limit=50" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# 特定時点以降のメッセージ
curl -X GET "http://localhost:8089/channels/channel-uuid-here/messages?after=2024-01-15T10:00:00Z" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# ページネーション
curl -X GET "http://localhost:8089/channels/channel-uuid-here/messages?page=1&limit=20" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
📊 データスキーマ
チャンネルエンティティ
interface Channel {
id: string; // 一意識別子
name: string; // チャンネル名(必須)
description?: string; // チャンネル説明
type: 'public' | 'private' | 'direct'; // チャンネルタイプ
createdBy: string; // 作成者ID
members: ChannelMember[]; // メンバーリスト
settings: ChannelSettings; // チャンネル設定
lastMessage?: {
id: string;
content: string;
timestamp: string;
senderId: string;
};
metadata?: Record<string, any>; // 追加メタデータ
createdAt: string; // 作成日時
updatedAt: string; // 更新日時
}
interface ChannelMember {
userId: string;
role: 'owner' | 'admin' | 'member';
joinedAt: string;
lastReadAt?: string;
notifications: boolean;
}
interface ChannelSettings {
allowFileSharing: boolean;
allowReactions: boolean;
messageHistory: boolean;
maxMessageLength: number;
allowedFileTypes?: string[];
}
メッセージエンティティ
interface Message {
id: string; // 一意識別子
channelId: string; // チャンネルID
senderId: string; // 送信者ID
content: string; // メッセージ内容
type: MessageType; // メッセージタイプ
replyTo?: string; // 返信先メッセージID
attachments?: Attachment[]; // 添付ファイル
reactions?: Reaction[]; // リアクション
mentions?: string[]; // メンション
edited?: {
at: string;
by: string;
};
metadata?: Record<string, any>; // 追加メタデータ
createdAt: string; // 作成日時
updatedAt: string; // 更新日時
}
type MessageType =
| 'text' // テキスト
| 'file' // ファイル
| 'image' // 画像
| 'system' // システムメッセージ
| 'call'; // 通話
interface Attachment {
filename: string;
url: string;
size: number;
mimeType: string;
thumbnail?: string;
}
interface Reaction {
emoji: string;
users: string[];
count: number;
}
🔍 高度な機能
メンション機能
# ユーザーメンション
curl -X POST http://localhost:8089/channels/channel-uuid-here/messages \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "@田中さん、資料の確認をお願いします。",
"type": "text",
"mentions": ["user-tanaka-uuid"]
}'
# 全員メンション
curl -X POST http://localhost:8089/channels/channel-uuid-here/messages \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "@channel 明日のミーティングは10時からです。",
"type": "text",
"mentions": ["@channel"]
}'
リアクション機能
# リアクション追加
curl -X POST http://localhost:8089/messages/message-uuid-here/reactions \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"emoji": "👍"
}'
# リアクション削除
curl -X DELETE http://localhost:8089/messages/message-uuid-here/reactions/👍 \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
検索機能
# メッセージ検索
curl -X GET "http://localhost:8089/search/messages?q=プロジェクト&channel=channel-uuid" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
# ファイル検索
curl -X GET "http://localhost:8089/search/files?type=pdf&channel=channel-uuid" \
-H "Authorization: Bearer USER_ACCESS_TOKEN"
🔧 設定オプション
チャンネル設定
interface ChatConfig {
maxMessageLength: number; // 最大メッセージ長
allowFileSharing: boolean; // ファイル共有許可
maxFileSize: number; // 最大ファイルサイズ
allowedFileTypes: string[]; // 許可ファイル形式
messageRetention: number; // メッセージ保持期間(日)
rateLimiting: {
messagesPerMinute: number; // 分間メッセージ数制限
filesPerHour: number; // 時間ファイル数制限
};
moderation: {
autoModeration: boolean; // 自動モデレーション
profanityFilter: boolean; // 不適切語句フィルター
spamDetection: boolean; // スパム検出
};
}
通知設定
const notificationSettings = {
mentions: true, // メンション通知
directMessages: true, // ダイレクトメッセージ通知
channelMessages: false, // チャンネルメッセージ通知
reactions: true, // リアクション通知
fileSharing: true, // ファイル共有通知
quiet: {
enabled: false,
startTime: '22:00',
endTime: '08:00'
}
};
🧪 テスト例
describe('チャットサービス', () => {
test('チャンネル作成が成功する', async () => {
const channelData = {
name: 'テストチャンネル',
type: 'public',
members: ['user-1-uuid', 'user-2-uuid']
};
const response = await request(chatApp)
.post('/channels')
.set('Authorization', `Bearer ${userToken}`)
.send(channelData)
.expect(201);
expect(response.body.message).toBe('チャンネルが正常に作成されました');
});
test('メッセージ送信が成功する', async () => {
const channel = await createTestChannel();
const messageData = {
content: 'テストメッセージ',
type: 'text'
};
const response = await request(chatApp)
.post(`/channels/${channel.id}/messages`)
.set('Authorization', `Bearer ${userToken}`)
.send(messageData)
.expect(201);
expect(response.body.message).toBe('メッセージが正常に送信されました');
});
test('非メンバーはメッセージを送信できない', async () => {
const privateChannel = await createPrivateChannel();
await request(chatApp)
.post(`/channels/${privateChannel.id}/messages`)
.set('Authorization', `Bearer ${nonMemberToken}`)
.send({ content: 'test', type: 'text' })
.expect(403);
});
});