Overview
Search for a single message by message ID, suitable for scenarios where you need to retrieve specific message details.Request Body
Required Parameters
Message ID
Copy
curl -X POST "http://localhost:5001/message" \
-H "Content-Type: application/json" \
-d '{
"message_id": 123456789
}'
Copy
{
"message_id": 123456789,
"message_seq": 1001,
"client_msg_no": "msg_123",
"from_uid": "user123",
"channel_id": "group123",
"channel_type": 2,
"timestamp": 1640995200,
"payload": "SGVsbG8gV29ybGQ="
}
Response Fields
Server-generated message ID
Message sequence number
Client message number
Sender user ID
Channel ID
Channel type
1- Personal channel2- Group channel
Message timestamp (Unix timestamp)
Base64 encoded message content
Status Codes
| Status Code | Description |
|---|---|
| 200 | Message search successful |
| 400 | Request parameter error |
| 404 | Message not found |
| 500 | Internal server error |
Use Cases
Message Detail Retrieval
Get Specific Message Details:Copy
// Retrieve details for a specific message
async function getMessageDetail(messageId) {
try {
const response = await fetch('/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message_id: messageId })
});
if (response.status === 404) {
return { found: false, message: null };
}
const message = await response.json();
// Decode and format message
const formattedMessage = {
...message,
content: atob(message.payload), // Decode base64 content
formatted_time: new Date(message.timestamp * 1000).toLocaleString(),
found: true
};
return formattedMessage;
} catch (error) {
console.error('Failed to get message detail:', error);
return { found: false, message: null, error: error.message };
}
}
// Usage
const messageDetail = await getMessageDetail(123456789);
if (messageDetail.found) {
console.log('Message content:', messageDetail.content);
console.log('Sent by:', messageDetail.from_uid);
console.log('Sent at:', messageDetail.formatted_time);
} else {
console.log('Message not found');
}
Message Verification
Verify Message Existence and Integrity:Copy
// Verify that a message exists and check its properties
async function verifyMessage(messageId, expectedProperties = {}) {
try {
const result = await getMessageDetail(messageId);
if (!result.found) {
return {
exists: false,
verified: false,
message: 'Message not found'
};
}
const message = result;
const verification = {
exists: true,
verified: true,
checks: {},
message: message
};
// Verify expected properties
for (const [key, expectedValue] of Object.entries(expectedProperties)) {
const actualValue = message[key];
const matches = actualValue === expectedValue;
verification.checks[key] = {
expected: expectedValue,
actual: actualValue,
matches: matches
};
if (!matches) {
verification.verified = false;
}
}
return verification;
} catch (error) {
return {
exists: false,
verified: false,
message: error.message
};
}
}
// Usage
const verification = await verifyMessage(123456789, {
from_uid: 'user123',
channel_id: 'group123',
channel_type: 2
});
if (verification.verified) {
console.log('Message verified successfully');
} else {
console.log('Verification failed:', verification.checks);
}
Message Reference Resolution
Resolve Message References:Copy
// Resolve message references in replies or quotes
async function resolveMessageReference(referenceId) {
try {
const message = await getMessageDetail(referenceId);
if (!message.found) {
return {
resolved: false,
reference: null,
display: '[Message not found]'
};
}
// Create a display-friendly reference
const reference = {
id: message.message_id,
sender: message.from_uid,
content: message.content.substring(0, 100), // Truncate for preview
timestamp: message.timestamp,
channel: message.channel_id,
display: `${message.from_uid}: ${message.content.substring(0, 50)}...`
};
return {
resolved: true,
reference: reference,
display: reference.display
};
} catch (error) {
return {
resolved: false,
reference: null,
display: '[Error loading message]'
};
}
}
// Usage in message rendering
async function renderMessageWithReferences(messageText) {
// Find message references in format @msg:123456789
const referencePattern = /@msg:(\d+)/g;
let match;
const references = [];
while ((match = referencePattern.exec(messageText)) !== null) {
const messageId = parseInt(match[1]);
const reference = await resolveMessageReference(messageId);
references.push({
original: match[0],
messageId: messageId,
reference: reference
});
}
// Replace references with display text
let renderedText = messageText;
for (const ref of references) {
renderedText = renderedText.replace(ref.original, ref.reference.display);
}
return {
originalText: messageText,
renderedText: renderedText,
references: references
};
}
Message Audit and Logging
Audit Message Access:Copy
// Audit message access for security and compliance
class MessageAuditor {
constructor() {
this.accessLog = [];
}
async getMessageWithAudit(messageId, accessorUserId, reason = 'general_access') {
const startTime = Date.now();
try {
const message = await getMessageDetail(messageId);
const endTime = Date.now();
// Log successful access
this.logAccess({
message_id: messageId,
accessor_user_id: accessorUserId,
reason: reason,
success: message.found,
timestamp: new Date().toISOString(),
response_time_ms: endTime - startTime,
message_found: message.found,
channel_id: message.found ? message.channel_id : null,
sender_uid: message.found ? message.from_uid : null
});
return message;
} catch (error) {
const endTime = Date.now();
// Log failed access
this.logAccess({
message_id: messageId,
accessor_user_id: accessorUserId,
reason: reason,
success: false,
timestamp: new Date().toISOString(),
response_time_ms: endTime - startTime,
error: error.message
});
throw error;
}
}
logAccess(logEntry) {
this.accessLog.push(logEntry);
// Send to audit system
this.sendToAuditSystem(logEntry);
// Clean up old logs (keep last 1000)
if (this.accessLog.length > 1000) {
this.accessLog = this.accessLog.slice(-1000);
}
}
async sendToAuditSystem(logEntry) {
try {
// Send to external audit system
await fetch('/audit/message-access', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(logEntry)
});
} catch (error) {
console.error('Failed to send audit log:', error);
}
}
getAccessStats() {
const stats = {
total_accesses: this.accessLog.length,
successful_accesses: this.accessLog.filter(log => log.success).length,
failed_accesses: this.accessLog.filter(log => !log.success).length,
unique_messages: new Set(this.accessLog.map(log => log.message_id)).size,
unique_accessors: new Set(this.accessLog.map(log => log.accessor_user_id)).size,
avg_response_time: this.accessLog.reduce((sum, log) => sum + log.response_time_ms, 0) / this.accessLog.length
};
return stats;
}
}
// Usage
const auditor = new MessageAuditor();
// Access message with audit trail
const message = await auditor.getMessageWithAudit(
123456789,
'admin_user',
'compliance_review'
);
// Get audit statistics
const stats = auditor.getAccessStats();
console.log('Audit stats:', stats);
Message Cache with Single Lookup
Efficient Single Message Caching:Copy
// Cache for single message lookups
class SingleMessageCache {
constructor(maxSize = 500, ttlMinutes = 30) {
this.cache = new Map();
this.maxSize = maxSize;
this.ttl = ttlMinutes * 60 * 1000; // Convert to milliseconds
}
async getMessage(messageId) {
// Check cache first
const cached = this.cache.get(messageId);
if (cached && this.isValid(cached)) {
cached.lastAccessed = Date.now();
return cached.message;
}
// Fetch from server
try {
const message = await getMessageDetail(messageId);
// Cache the result (even if not found)
this.addToCache(messageId, message);
return message;
} catch (error) {
// Cache error result temporarily
this.addToCache(messageId, {
found: false,
error: error.message
}, 5 * 60 * 1000); // 5 minute TTL for errors
throw error;
}
}
addToCache(messageId, message, customTtl = null) {
// Remove oldest if cache is full
if (this.cache.size >= this.maxSize) {
this.evictOldest();
}
const cacheEntry = {
message: message,
timestamp: Date.now(),
lastAccessed: Date.now(),
ttl: customTtl || this.ttl
};
this.cache.set(messageId, cacheEntry);
}
isValid(cacheEntry) {
const age = Date.now() - cacheEntry.timestamp;
return age < cacheEntry.ttl;
}
evictOldest() {
let oldestKey = null;
let oldestTime = Date.now();
for (const [key, entry] of this.cache) {
if (entry.lastAccessed < oldestTime) {
oldestTime = entry.lastAccessed;
oldestKey = key;
}
}
if (oldestKey) {
this.cache.delete(oldestKey);
}
}
getCacheStats() {
const now = Date.now();
const validEntries = Array.from(this.cache.values()).filter(entry =>
this.isValid(entry)
);
return {
total_entries: this.cache.size,
valid_entries: validEntries.length,
expired_entries: this.cache.size - validEntries.length,
hit_rate: this.hitRate || 0,
memory_usage: this.cache.size / this.maxSize * 100
};
}
}
// Usage
const messageCache = new SingleMessageCache(1000, 60); // 1000 messages, 60 minute TTL
// Get message (will cache result)
const message1 = await messageCache.getMessage(123456789);
console.log('First access:', message1.found);
// Get same message (will use cache)
const message2 = await messageCache.getMessage(123456789);
console.log('Second access (cached):', message2.found);
console.log('Cache stats:', messageCache.getCacheStats());
Best Practices
- Error Handling: Always handle 404 responses when message might not exist
- Caching: Cache frequently accessed messages to reduce API calls
- Validation: Validate message ID format before making requests
- Security: Implement proper access controls for message retrieval
- Audit Trail: Log message access for security and compliance
- Performance: Use batch search for multiple messages instead of individual calls
- Content Decoding: Remember to decode base64 payload content for display

