0
# API Endpoints
1
2
JSON API endpoints for real-time notification features including unread counts, notification lists, and AJAX-powered live updates for single-page applications and mobile apps.
3
4
## Capabilities
5
6
### Notification Count Endpoints
7
8
JSON endpoints that return notification counts for authenticated users with caching and performance optimization.
9
10
```python { .api }
11
@never_cache
12
def live_unread_notification_count(request):
13
"""
14
Return JSON with unread notification count for authenticated user.
15
16
Args:
17
request: Django HTTP request object
18
19
Returns:
20
JsonResponse: {"unread_count": <number>}
21
22
Response for unauthenticated users:
23
{"unread_count": 0}
24
25
Example response:
26
{"unread_count": 5}
27
"""
28
29
@never_cache
30
def live_all_notification_count(request):
31
"""
32
Return JSON with total notification count for authenticated user.
33
34
Args:
35
request: Django HTTP request object
36
37
Returns:
38
JsonResponse: {"all_count": <number>}
39
40
Response for unauthenticated users:
41
{"all_count": 0}
42
43
Example response:
44
{"all_count": 25}
45
"""
46
```
47
48
### Notification List Endpoints
49
50
JSON endpoints that return formatted notification lists with configurable limits and optional mark-as-read functionality.
51
52
```python { .api }
53
@never_cache
54
def live_unread_notification_list(request):
55
"""
56
Return JSON with unread notification list and count.
57
58
Args:
59
request: Django HTTP request object
60
61
Query Parameters:
62
max (int, optional): Maximum notifications to return (1-100, default from settings)
63
mark_as_read (str, optional): Mark returned notifications as read if present
64
65
Returns:
66
JsonResponse: {
67
"unread_count": <number>,
68
"unread_list": [<notification_objects>]
69
}
70
71
Response for unauthenticated users:
72
{"unread_count": 0, "unread_list": []}
73
74
Example response:
75
{
76
"unread_count": 3,
77
"unread_list": [
78
{
79
"id": 123,
80
"slug": 110909,
81
"actor": "John Doe",
82
"verb": "liked",
83
"target": "My Blog Post",
84
"action_object": null,
85
"description": "John liked your post",
86
"timestamp": "2023-01-15T10:30:00Z",
87
"unread": true,
88
"level": "info",
89
"data": {}
90
},
91
// ... more notifications
92
]
93
}
94
"""
95
96
@never_cache
97
def live_all_notification_list(request):
98
"""
99
Return JSON with all notification list and count.
100
101
Args:
102
request: Django HTTP request object
103
104
Query Parameters:
105
max (int, optional): Maximum notifications to return (1-100, default from settings)
106
mark_as_read (str, optional): Mark returned notifications as read if present
107
108
Returns:
109
JsonResponse: {
110
"all_count": <number>,
111
"all_list": [<notification_objects>]
112
}
113
114
Response for unauthenticated users:
115
{"all_count": 0, "all_list": []}
116
117
Example response:
118
{
119
"all_count": 25,
120
"all_list": [
121
{
122
"id": 123,
123
"slug": 110909,
124
"actor": "John Doe",
125
"verb": "liked",
126
"target": "My Blog Post",
127
"action_object": null,
128
"description": "John liked your post",
129
"timestamp": "2023-01-15T10:30:00Z",
130
"unread": false,
131
"level": "info",
132
"data": {}
133
},
134
// ... more notifications
135
]
136
}
137
"""
138
```
139
140
### Usage Examples
141
142
#### Basic AJAX Requests
143
144
```javascript
145
// Get unread notification count
146
async function getUnreadCount() {
147
try {
148
const response = await fetch('/inbox/notifications/api/unread_count/');
149
const data = await response.json();
150
return data.unread_count;
151
} catch (error) {
152
console.error('Error fetching unread count:', error);
153
return 0;
154
}
155
}
156
157
// Get unread notification list
158
async function getUnreadNotifications(maxCount = 10) {
159
try {
160
const response = await fetch(`/inbox/notifications/api/unread_list/?max=${maxCount}`);
161
const data = await response.json();
162
return data;
163
} catch (error) {
164
console.error('Error fetching notifications:', error);
165
return { unread_count: 0, unread_list: [] };
166
}
167
}
168
169
// Get all notifications
170
async function getAllNotifications(maxCount = 20) {
171
try {
172
const response = await fetch(`/inbox/notifications/api/all_list/?max=${maxCount}`);
173
const data = await response.json();
174
return data;
175
} catch (error) {
176
console.error('Error fetching all notifications:', error);
177
return { all_count: 0, all_list: [] };
178
}
179
}
180
```
181
182
#### Live Notification Badge
183
184
```javascript
185
class NotificationBadge {
186
constructor(badgeElement, apiUrl = '/inbox/notifications/api/unread_count/') {
187
this.badge = badgeElement;
188
this.apiUrl = apiUrl;
189
this.updateInterval = 30000; // 30 seconds
190
this.startPolling();
191
}
192
193
async updateBadge() {
194
try {
195
const response = await fetch(this.apiUrl);
196
const data = await response.json();
197
const count = data.unread_count;
198
199
this.badge.textContent = count;
200
this.badge.style.display = count > 0 ? 'inline' : 'none';
201
202
// Add visual indication for new notifications
203
if (count > this.lastCount) {
204
this.badge.classList.add('pulse');
205
setTimeout(() => this.badge.classList.remove('pulse'), 1000);
206
}
207
208
this.lastCount = count;
209
} catch (error) {
210
console.error('Failed to update notification badge:', error);
211
}
212
}
213
214
startPolling() {
215
this.updateBadge(); // Initial update
216
this.intervalId = setInterval(() => this.updateBadge(), this.updateInterval);
217
}
218
219
stopPolling() {
220
if (this.intervalId) {
221
clearInterval(this.intervalId);
222
}
223
}
224
}
225
226
// Usage
227
const badge = document.querySelector('.notification-badge');
228
const notificationBadge = new NotificationBadge(badge);
229
```
230
231
#### Live Notification List
232
233
```javascript
234
class NotificationList {
235
constructor(containerElement, apiUrl = '/inbox/notifications/api/unread_list/') {
236
this.container = containerElement;
237
this.apiUrl = apiUrl;
238
this.updateInterval = 15000; // 15 seconds
239
this.startPolling();
240
}
241
242
async updateList() {
243
try {
244
const response = await fetch(`${this.apiUrl}?max=10`);
245
const data = await response.json();
246
247
this.renderNotifications(data.unread_list);
248
this.updateCount(data.unread_count);
249
} catch (error) {
250
console.error('Failed to update notification list:', error);
251
}
252
}
253
254
renderNotifications(notifications) {
255
this.container.innerHTML = '';
256
257
if (notifications.length === 0) {
258
this.container.innerHTML = '<li class="no-notifications">No new notifications</li>';
259
return;
260
}
261
262
notifications.forEach(notification => {
263
const li = document.createElement('li');
264
li.className = 'notification-item';
265
li.innerHTML = `
266
<div class="notification-content">
267
<strong>${notification.actor}</strong> ${notification.verb}
268
${notification.target ? ` ${notification.target}` : ''}
269
<small>${this.formatTime(notification.timestamp)}</small>
270
</div>
271
<div class="notification-actions">
272
<button onclick="markAsRead(${notification.slug})">Mark as Read</button>
273
</div>
274
`;
275
this.container.appendChild(li);
276
});
277
}
278
279
formatTime(timestamp) {
280
const date = new Date(timestamp);
281
const now = new Date();
282
const diffMs = now - date;
283
const diffMins = Math.floor(diffMs / 60000);
284
285
if (diffMins < 1) return 'just now';
286
if (diffMins < 60) return `${diffMins}m ago`;
287
if (diffMins < 1440) return `${Math.floor(diffMins / 60)}h ago`;
288
return `${Math.floor(diffMins / 1440)}d ago`;
289
}
290
291
updateCount(count) {
292
const countElement = document.querySelector('.notification-count');
293
if (countElement) {
294
countElement.textContent = count;
295
}
296
}
297
298
startPolling() {
299
this.updateList(); // Initial load
300
this.intervalId = setInterval(() => this.updateList(), this.updateInterval);
301
}
302
303
stopPolling() {
304
if (this.intervalId) {
305
clearInterval(this.intervalId);
306
}
307
}
308
}
309
310
// Usage
311
const listContainer = document.querySelector('.notification-list');
312
const notificationList = new NotificationList(listContainer);
313
```
314
315
#### Mark as Read with API
316
317
```javascript
318
// Get notifications and mark them as read
319
async function getAndMarkNotifications() {
320
try {
321
const response = await fetch('/inbox/notifications/api/unread_list/?mark_as_read=true');
322
const data = await response.json();
323
324
// Process notifications that were automatically marked as read
325
console.log(`Retrieved and marked ${data.unread_list.length} notifications as read`);
326
return data;
327
} catch (error) {
328
console.error('Error:', error);
329
}
330
}
331
```
332
333
#### Real-time Dashboard Widget
334
335
```javascript
336
class NotificationWidget {
337
constructor(options = {}) {
338
this.options = {
339
updateInterval: 30000,
340
maxNotifications: 5,
341
showBadge: true,
342
showList: true,
343
...options
344
};
345
346
this.init();
347
}
348
349
init() {
350
this.createWidget();
351
this.startUpdates();
352
}
353
354
createWidget() {
355
this.widget = document.createElement('div');
356
this.widget.className = 'notification-widget';
357
this.widget.innerHTML = `
358
<div class="widget-header">
359
<span>Notifications</span>
360
${this.options.showBadge ? '<span class="badge">0</span>' : ''}
361
</div>
362
${this.options.showList ? '<ul class="notification-list"></ul>' : ''}
363
`;
364
document.body.appendChild(this.widget);
365
}
366
367
async update() {
368
const [countData, listData] = await Promise.all([
369
fetch('/inbox/notifications/api/unread_count/').then(r => r.json()),
370
this.options.showList ?
371
fetch(`/inbox/notifications/api/unread_list/?max=${this.options.maxNotifications}`)
372
.then(r => r.json()) :
373
Promise.resolve(null)
374
]);
375
376
// Update badge
377
if (this.options.showBadge) {
378
const badge = this.widget.querySelector('.badge');
379
badge.textContent = countData.unread_count;
380
badge.style.display = countData.unread_count > 0 ? 'inline' : 'none';
381
}
382
383
// Update list
384
if (this.options.showList && listData) {
385
this.renderList(listData.unread_list);
386
}
387
}
388
389
renderList(notifications) {
390
const list = this.widget.querySelector('.notification-list');
391
list.innerHTML = notifications.map(n => `
392
<li class="notification-item" data-id="${n.id}">
393
<div class="notification-text">
394
${n.description || `${n.actor} ${n.verb}`}
395
</div>
396
<div class="notification-time">
397
${this.formatTime(n.timestamp)}
398
</div>
399
</li>
400
`).join('');
401
}
402
403
formatTime(timestamp) {
404
return new Date(timestamp).toLocaleDateString();
405
}
406
407
startUpdates() {
408
this.update(); // Initial update
409
this.intervalId = setInterval(() => this.update(), this.options.updateInterval);
410
}
411
412
destroy() {
413
if (this.intervalId) {
414
clearInterval(this.intervalId);
415
}
416
if (this.widget) {
417
this.widget.remove();
418
}
419
}
420
}
421
422
// Usage
423
const widget = new NotificationWidget({
424
updateInterval: 20000, // Update every 20 seconds
425
maxNotifications: 8,
426
showBadge: true,
427
showList: true
428
});
429
```
430
431
#### Error Handling and Fallbacks
432
433
```javascript
434
class RobustNotificationClient {
435
constructor() {
436
this.retryCount = 0;
437
this.maxRetries = 3;
438
this.retryDelay = 5000;
439
}
440
441
async fetchWithRetry(url, options = {}) {
442
try {
443
const response = await fetch(url, options);
444
445
if (!response.ok) {
446
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
447
}
448
449
this.retryCount = 0; // Reset on success
450
return await response.json();
451
} catch (error) {
452
if (this.retryCount < this.maxRetries) {
453
this.retryCount++;
454
console.warn(`Fetch failed, retrying in ${this.retryDelay}ms (attempt ${this.retryCount}/${this.maxRetries})`);
455
456
await new Promise(resolve => setTimeout(resolve, this.retryDelay));
457
return this.fetchWithRetry(url, options);
458
} else {
459
console.error('Max retries exceeded:', error);
460
throw error;
461
}
462
}
463
}
464
465
async getNotifications() {
466
try {
467
return await this.fetchWithRetry('/inbox/notifications/api/unread_list/');
468
} catch (error) {
469
// Return fallback data
470
return { unread_count: 0, unread_list: [] };
471
}
472
}
473
}
474
```