Facebook Messenger - API Design
API Architecture Overview
API Design Principles
- RESTful Design: Standard HTTP methods and status codes
- Real-time First: WebSocket APIs for real-time communication
- GraphQL Integration: Flexible data fetching for complex queries
- Versioning Strategy: Backward-compatible API evolution
- Rate Limiting: Protect against abuse and ensure fair usage
- Security First: Authentication, authorization, and data protection
API Gateway Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client Apps │ │ API Gateway │ │ Microservices │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ REST Client │ ├────┤ │ Rate Limit │ ├────┤ │ User Service│ │
│ └─────────────┘ │ │ │ Auth │ │ │ └─────────────┘ │
│ │ │ │ Validation │ │ │ │
│ ┌─────────────┐ │ │ │ Routing │ │ │ ┌─────────────┐ │
│ │ WebSocket │ ├────┤ │ Monitoring │ ├────┤ │ Message Svc │ │
│ │ Client │ │ │ └─────────────┘ │ │ └─────────────┘ │
│ └─────────────┘ │ │ │ │ │
│ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ ┌─────────────┐ │ │ │ GraphQL │ ├────┤ │ Media Svc │ │
│ │ GraphQL │ ├────┤ │ Gateway │ │ │ └─────────────┘ │
│ │ Client │ │ │ └─────────────┘ │ │ │
│ └─────────────┘ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘Authentication and Authorization APIs
Authentication Endpoints
User Login
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "secure_password",
"device_id": "device_uuid",
"device_type": "mobile",
"platform": "ios"
}
Response:
{
"access_token": "jwt_access_token",
"refresh_token": "jwt_refresh_token",
"expires_in": 3600,
"user": {
"user_id": 123456,
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"profile_picture_url": "https://cdn.messenger.com/profiles/123456.jpg"
}
}Token Refresh
POST /api/v1/auth/refresh
Content-Type: application/json
Authorization: Bearer refresh_token
{
"refresh_token": "jwt_refresh_token"
}
Response:
{
"access_token": "new_jwt_access_token",
"expires_in": 3600
}OAuth Integration
POST /api/v1/auth/facebook
Content-Type: application/json
{
"facebook_access_token": "facebook_token",
"device_id": "device_uuid",
"device_type": "web"
}
Response:
{
"access_token": "jwt_access_token",
"refresh_token": "jwt_refresh_token",
"expires_in": 3600,
"is_new_user": false,
"user": { /* user object */ }
}Authorization Middleware
// JWT Token Validation
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).json({ error: 'Invalid token' });
req.user = user;
next();
});
};
// Rate Limiting
const rateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000, // limit each IP to 1000 requests per windowMs
message: 'Too many requests from this IP'
});REST API Endpoints
User Management APIs
Get User Profile
GET /api/v1/users/{user_id}
Authorization: Bearer jwt_token
Response:
{
"user_id": 123456,
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"profile_picture_url": "https://cdn.messenger.com/profiles/123456.jpg",
"status_message": "Available",
"last_active_at": "2024-01-03T19:30:00Z",
"privacy_settings": {
"show_last_seen": true,
"show_online_status": true
}
}Update User Profile
PUT /api/v1/users/{user_id}
Authorization: Bearer jwt_token
Content-Type: application/json
{
"first_name": "John",
"last_name": "Smith",
"status_message": "Busy",
"privacy_settings": {
"show_last_seen": false,
"show_online_status": true
}
}
Response:
{
"success": true,
"user": { /* updated user object */ }
}Search Users
GET /api/v1/users/search?q=john&limit=20&offset=0
Authorization: Bearer jwt_token
Response:
{
"users": [
{
"user_id": 123456,
"username": "johndoe",
"first_name": "John",
"last_name": "Doe",
"profile_picture_url": "https://cdn.messenger.com/profiles/123456.jpg",
"mutual_friends_count": 5
}
],
"total_count": 1,
"has_more": false
}Conversation Management APIs
Get Conversations List
GET /api/v1/conversations?limit=50&cursor=eyJsYXN0X21lc3NhZ2VfYXQiOiIyMDI0LTAxLTAz...
Authorization: Bearer jwt_token
Response:
{
"conversations": [
{
"conversation_id": 1001,
"conversation_type": "direct",
"title": null,
"participants": [
{
"user_id": 123456,
"first_name": "John",
"last_name": "Doe",
"profile_picture_url": "https://cdn.messenger.com/profiles/123456.jpg"
}
],
"last_message": {
"message_id": "01234567-89ab-cdef-0123-456789abcdef",
"sender_id": 123456,
"content": "Hey, how are you?",
"created_at": "2024-01-03T19:30:00Z",
"message_type": "text"
},
"unread_count": 2,
"last_read_message_id": "01234567-89ab-cdef-0123-456789abcdef",
"updated_at": "2024-01-03T19:30:00Z"
}
],
"next_cursor": "eyJsYXN0X21lc3NhZ2VfYXQiOiIyMDI0LTAxLTAz...",
"has_more": true
}Create Conversation
POST /api/v1/conversations
Authorization: Bearer jwt_token
Content-Type: application/json
{
"conversation_type": "group",
"title": "Project Team",
"participant_ids": [123456, 789012, 345678],
"description": "Discussion for the new project"
}
Response:
{
"conversation_id": 1002,
"conversation_type": "group",
"title": "Project Team",
"description": "Discussion for the new project",
"created_by": 111111,
"created_at": "2024-01-03T19:30:00Z",
"participants": [ /* participant objects */ ]
}Add/Remove Participants
POST /api/v1/conversations/{conversation_id}/participants
Authorization: Bearer jwt_token
Content-Type: application/json
{
"action": "add",
"user_ids": [456789, 987654]
}
Response:
{
"success": true,
"added_participants": [
{
"user_id": 456789,
"first_name": "Jane",
"last_name": "Smith",
"joined_at": "2024-01-03T19:30:00Z"
}
]
}Message Management APIs
Get Message History
GET /api/v1/conversations/{conversation_id}/messages?limit=50&before=01234567-89ab-cdef-0123-456789abcdef
Authorization: Bearer jwt_token
Response:
{
"messages": [
{
"message_id": "01234567-89ab-cdef-0123-456789abcdef",
"conversation_id": 1001,
"sender_id": 123456,
"message_type": "text",
"content": "Hello there!",
"created_at": "2024-01-03T19:30:00Z",
"updated_at": "2024-01-03T19:30:00Z",
"delivery_status": "read",
"reactions": {
"👍": [123456, 789012],
"❤️": [345678]
},
"reply_to_message_id": null,
"media_attachments": []
}
],
"has_more": true,
"next_cursor": "eyJtZXNzYWdlX2lkIjoiMDEyMzQ1Njc..."
}Send Message
POST /api/v1/conversations/{conversation_id}/messages
Authorization: Bearer jwt_token
Content-Type: application/json
{
"message_type": "text",
"content": "Hello everyone!",
"reply_to_message_id": "01234567-89ab-cdef-0123-456789abcdef",
"client_message_id": "client_generated_uuid"
}
Response:
{
"message_id": "fedcba98-7654-3210-fedc-ba9876543210",
"conversation_id": 1001,
"sender_id": 111111,
"message_type": "text",
"content": "Hello everyone!",
"created_at": "2024-01-03T19:30:00Z",
"delivery_status": "sent",
"client_message_id": "client_generated_uuid"
}Edit Message
PUT /api/v1/messages/{message_id}
Authorization: Bearer jwt_token
Content-Type: application/json
{
"content": "Hello everyone! (edited)",
"edit_reason": "typo_correction"
}
Response:
{
"success": true,
"message": {
"message_id": "fedcba98-7654-3210-fedc-ba9876543210",
"content": "Hello everyone! (edited)",
"updated_at": "2024-01-03T19:31:00Z",
"edit_history": [
{
"edited_at": "2024-01-03T19:31:00Z",
"previous_content": "Hello everyone!",
"edit_reason": "typo_correction"
}
]
}
}Add Reaction
POST /api/v1/messages/{message_id}/reactions
Authorization: Bearer jwt_token
Content-Type: application/json
{
"emoji": "👍"
}
Response:
{
"success": true,
"reactions": {
"👍": [111111, 123456],
"❤️": [789012]
}
}Media Upload APIs
Upload Media File
POST /api/v1/media/upload
Authorization: Bearer jwt_token
Content-Type: multipart/form-data
file: [binary file data]
conversation_id: 1001
message_type: image
Response:
{
"file_id": "media_uuid",
"file_type": "image/jpeg",
"file_size": 2048576,
"file_url": "https://cdn.messenger.com/media/media_uuid.jpg",
"thumbnail_url": "https://cdn.messenger.com/thumbs/media_uuid_thumb.jpg",
"dimensions": {
"width": 1920,
"height": 1080
},
"processing_status": "completed"
}Send Media Message
POST /api/v1/conversations/{conversation_id}/messages
Authorization: Bearer jwt_token
Content-Type: application/json
{
"message_type": "image",
"content": "Check out this photo!",
"media_attachments": [
{
"file_id": "media_uuid",
"file_type": "image/jpeg",
"file_url": "https://cdn.messenger.com/media/media_uuid.jpg",
"thumbnail_url": "https://cdn.messenger.com/thumbs/media_uuid_thumb.jpg"
}
]
}WebSocket API for Real-time Communication
WebSocket Connection Flow
// Client connection establishment
const ws = new WebSocket('wss://ws.messenger.com/v1/connect');
// Authentication after connection
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'auth',
token: 'jwt_access_token',
device_id: 'device_uuid'
}));
};
// Handle authentication response
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch(message.type) {
case 'auth_success':
console.log('Authenticated successfully');
subscribeToConversations();
break;
case 'auth_error':
console.error('Authentication failed:', message.error);
break;
}
};WebSocket Message Types
Subscribe to Conversations
{
"type": "subscribe",
"conversation_ids": [1001, 1002, 1003],
"request_id": "client_request_uuid"
}
Response:
{
"type": "subscribe_success",
"request_id": "client_request_uuid",
"subscribed_conversations": [1001, 1002, 1003]
}Send Real-time Message
{
"type": "send_message",
"conversation_id": 1001,
"message_type": "text",
"content": "Hello in real-time!",
"client_message_id": "client_uuid",
"request_id": "request_uuid"
}
Response:
{
"type": "message_sent",
"request_id": "request_uuid",
"message_id": "server_generated_uuid",
"client_message_id": "client_uuid",
"timestamp": "2024-01-03T19:30:00Z"
}Receive Real-time Message
{
"type": "new_message",
"conversation_id": 1001,
"message": {
"message_id": "server_generated_uuid",
"sender_id": 123456,
"message_type": "text",
"content": "Hello back!",
"created_at": "2024-01-03T19:30:00Z",
"delivery_status": "sent"
}
}Typing Indicators
// Start typing
{
"type": "typing_start",
"conversation_id": 1001
}
// Stop typing
{
"type": "typing_stop",
"conversation_id": 1001
}
// Receive typing notification
{
"type": "user_typing",
"conversation_id": 1001,
"user_id": 123456,
"is_typing": true
}Presence Updates
// Update presence
{
"type": "presence_update",
"status": "online"
}
// Receive presence notification
{
"type": "presence_changed",
"user_id": 123456,
"status": "away",
"last_seen": "2024-01-03T19:25:00Z"
}Message Delivery Receipts
// Mark message as delivered
{
"type": "message_delivered",
"message_id": "server_generated_uuid",
"conversation_id": 1001
}
// Mark message as read
{
"type": "message_read",
"message_id": "server_generated_uuid",
"conversation_id": 1001
}
// Receive delivery status update
{
"type": "delivery_status_update",
"message_id": "server_generated_uuid",
"conversation_id": 1001,
"user_id": 123456,
"status": "read",
"timestamp": "2024-01-03T19:30:00Z"
}GraphQL API Design
Schema Definition
type User {
id: ID!
username: String!
firstName: String!
lastName: String!
profilePictureUrl: String
statusMessage: String
lastActiveAt: DateTime
isOnline: Boolean!
}
type Conversation {
id: ID!
type: ConversationType!
title: String
participants: [User!]!
messages(first: Int, after: String): MessageConnection!
lastMessage: Message
unreadCount: Int!
updatedAt: DateTime!
}
type Message {
id: ID!
conversationId: ID!
sender: User!
type: MessageType!
content: String
mediaAttachments: [MediaAttachment!]!
reactions: [Reaction!]!
replyTo: Message
createdAt: DateTime!
updatedAt: DateTime!
deliveryStatus: DeliveryStatus!
}
type Query {
me: User!
conversations(first: Int, after: String): ConversationConnection!
conversation(id: ID!): Conversation
searchUsers(query: String!, first: Int): UserConnection!
searchMessages(query: String!, conversationId: ID, first: Int): MessageConnection!
}
type Mutation {
sendMessage(input: SendMessageInput!): SendMessagePayload!
editMessage(id: ID!, content: String!): EditMessagePayload!
deleteMessage(id: ID!): DeleteMessagePayload!
addReaction(messageId: ID!, emoji: String!): AddReactionPayload!
createConversation(input: CreateConversationInput!): CreateConversationPayload!
updatePresence(status: PresenceStatus!): UpdatePresencePayload!
}
type Subscription {
messageAdded(conversationId: ID!): Message!
messageUpdated(conversationId: ID!): Message!
presenceChanged(userId: ID!): PresenceUpdate!
typingIndicator(conversationId: ID!): TypingIndicator!
}GraphQL Query Examples
# Get conversations with recent messages
query GetConversations {
conversations(first: 20) {
edges {
node {
id
type
title
participants {
id
firstName
lastName
profilePictureUrl
isOnline
}
lastMessage {
id
content
sender {
firstName
}
createdAt
}
unreadCount
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
# Send a message
mutation SendMessage($input: SendMessageInput!) {
sendMessage(input: $input) {
message {
id
content
createdAt
deliveryStatus
}
errors {
field
message
}
}
}
# Subscribe to new messages
subscription MessageAdded($conversationId: ID!) {
messageAdded(conversationId: $conversationId) {
id
content
sender {
id
firstName
}
createdAt
}
}Push Notification APIs
Register Device for Notifications
POST /api/v1/notifications/devices
Authorization: Bearer jwt_token
Content-Type: application/json
{
"device_token": "apns_or_fcm_token",
"platform": "ios", // or "android"
"device_id": "device_uuid",
"app_version": "1.2.3"
}
Response:
{
"success": true,
"device_id": "device_uuid",
"registered_at": "2024-01-03T19:30:00Z"
}Update Notification Preferences
PUT /api/v1/notifications/preferences
Authorization: Bearer jwt_token
Content-Type: application/json
{
"global_notifications": true,
"message_notifications": true,
"group_notifications": true,
"quiet_hours": {
"enabled": true,
"start_time": "22:00",
"end_time": "08:00",
"timezone": "America/New_York"
},
"conversation_preferences": {
"1001": {
"notifications_enabled": false
}
}
}Rate Limiting and Error Handling
Rate Limiting Headers
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1641234567
X-RateLimit-Window: 900Error Response Format
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": [
{
"field": "content",
"message": "Message content cannot be empty"
}
],
"request_id": "req_uuid",
"timestamp": "2024-01-03T19:30:00Z"
}
}Common HTTP Status Codes
- 200 OK: Successful request
- 201 Created: Resource created successfully
- 400 Bad Request: Invalid request parameters
- 401 Unauthorized: Authentication required
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Resource not found
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server error
- 503 Service Unavailable: Service temporarily unavailable
This comprehensive API design provides a robust foundation for building a scalable messaging platform with real-time capabilities, efficient data fetching, and excellent developer experience.