soajs.controller 4.3.4 → 4.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Gruntfile.js +1 -1
- package/docs/configuration-custom-registry.md +159 -9
- package/docs/middleware/cache.md +275 -0
- package/docs/middleware/idempotency.md +209 -0
- package/docs/request-flow.md +35 -4
- package/lib/request.js +5 -0
- package/mw/cache/index.js +175 -0
- package/mw/cache/model/memory.js +121 -0
- package/mw/cache/model/mongo.js +98 -0
- package/mw/gotoService/redirectToService.js +77 -16
- package/mw/idempotency/index.js +171 -0
- package/mw/idempotency/model/memory.js +132 -0
- package/mw/idempotency/model/mongo.js +116 -0
- package/mw/traffic/model/memory.js +4 -0
- package/package.json +1 -1
- package/server/controller.js +14 -0
- package/test/unit/index.js +4 -0
- package/test/unit/mw/cache/index.js +578 -0
- package/test/unit/mw/cache/memory.js +143 -0
- package/test/unit/mw/idempotency/index.js +354 -0
- package/test/unit/mw/idempotency/memory.js +151 -0
package/Gruntfile.js
CHANGED
|
@@ -16,6 +16,15 @@ registry.custom
|
|
|
16
16
|
│ │ ├── model # Throttling storage backend
|
|
17
17
|
│ │ ├── ip2ban # Banned IP addresses
|
|
18
18
|
│ │ └── throttling # Service-level rate limiting
|
|
19
|
+
│ ├── idempotency # Idempotency key configuration
|
|
20
|
+
│ │ ├── model # Storage backend (memory/mongo)
|
|
21
|
+
│ │ └── services # Per-service idempotency config
|
|
22
|
+
│ │ └── [service] # Service-specific settings
|
|
23
|
+
│ ├── cache # GET response caching
|
|
24
|
+
│ │ ├── model # Storage backend (memory/mongo)
|
|
25
|
+
│ │ ├── defaultTTL # Default cache TTL
|
|
26
|
+
│ │ └── services # Per-service cache config
|
|
27
|
+
│ │ └── [service] # Service-specific settings
|
|
19
28
|
│ ├── maintenanceMode # Gateway maintenance mode
|
|
20
29
|
│ ├── lastSeen # User activity tracking
|
|
21
30
|
│ └── gotoService
|
|
@@ -122,7 +131,123 @@ Configures rate limiting strategies and storage backend.
|
|
|
122
131
|
|
|
123
132
|
---
|
|
124
133
|
|
|
125
|
-
## 4.
|
|
134
|
+
## 4. Idempotency
|
|
135
|
+
|
|
136
|
+
**Path:** `registry.custom.gateway.value.idempotency`
|
|
137
|
+
|
|
138
|
+
**Middleware:** `mw/idempotency/index.js`
|
|
139
|
+
|
|
140
|
+
Prevents duplicate write operations by tracking requests via `Idempotency-Key` headers. When a client retries a request with the same key, the cached response is returned without re-executing the operation.
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
{
|
|
144
|
+
"idempotency": {
|
|
145
|
+
"model": "memory", // Storage: "memory" or "mongo"
|
|
146
|
+
"services": { // Per-service configuration
|
|
147
|
+
"av": { // Service name
|
|
148
|
+
"enabled": true, // Enable for this service
|
|
149
|
+
"ttl": 60000, // Key expiration (ms)
|
|
150
|
+
"apis": [ // APIs to protect
|
|
151
|
+
"POST /calls",
|
|
152
|
+
"PUT /call/p2p/ended",
|
|
153
|
+
"PUT /call/p2p/rejected"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
"payment": {
|
|
157
|
+
"enabled": true,
|
|
158
|
+
"ttl": 120000,
|
|
159
|
+
"apis": [
|
|
160
|
+
"POST /charge",
|
|
161
|
+
"POST /refund"
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Field | Type | Default | Description |
|
|
170
|
+
|-------|------|---------|-------------|
|
|
171
|
+
| `model` | string | `"memory"` | Storage backend: `"memory"` or `"mongo"` |
|
|
172
|
+
| `services.[name].enabled` | boolean | `false` | Enable idempotency for this service |
|
|
173
|
+
| `services.[name].ttl` | number | `60000` | Key expiration time in milliseconds |
|
|
174
|
+
| `services.[name].apis` | string[] | `[]` | API patterns to protect (e.g., `"POST /path"`) |
|
|
175
|
+
|
|
176
|
+
**Client Usage:**
|
|
177
|
+
```http
|
|
178
|
+
POST /av/calls HTTP/1.1
|
|
179
|
+
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Error Codes:**
|
|
183
|
+
- `180` (400): Invalid Idempotency-Key format (not UUID v4)
|
|
184
|
+
- `181` (409): Request with this key is still being processed
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 5. Response Caching
|
|
189
|
+
|
|
190
|
+
**Path:** `registry.custom.gateway.value.cache`
|
|
191
|
+
|
|
192
|
+
**Middleware:** `mw/cache/index.js`
|
|
193
|
+
|
|
194
|
+
Caches GET API responses with per-API TTL configuration. Returns `X-Cache: HIT` or `X-Cache: MISS` headers.
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
{
|
|
198
|
+
"cache": {
|
|
199
|
+
"model": "memory", // Storage: "memory" or "mongo"
|
|
200
|
+
"defaultTTL": 300000, // Default TTL: 5 minutes
|
|
201
|
+
"services": { // Per-service configuration
|
|
202
|
+
"av": { // Service name
|
|
203
|
+
"enabled": true, // Enable caching for this service
|
|
204
|
+
"apis": {
|
|
205
|
+
"GET /calls": {
|
|
206
|
+
"enabled": true,
|
|
207
|
+
"ttl": 30000 // 30 seconds
|
|
208
|
+
},
|
|
209
|
+
"GET /call/:id": {
|
|
210
|
+
"enabled": true,
|
|
211
|
+
"ttl": 60000 // 60 seconds
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"catalog": {
|
|
216
|
+
"enabled": true,
|
|
217
|
+
"apis": {
|
|
218
|
+
"GET /products": {
|
|
219
|
+
"enabled": true,
|
|
220
|
+
"ttl": 600000 // 10 minutes
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
| Field | Type | Default | Description |
|
|
230
|
+
|-------|------|---------|-------------|
|
|
231
|
+
| `model` | string | `"memory"` | Storage backend: `"memory"` or `"mongo"` |
|
|
232
|
+
| `defaultTTL` | number | `300000` | Default cache TTL in milliseconds |
|
|
233
|
+
| `services.[name].enabled` | boolean | `false` | Enable caching for this service |
|
|
234
|
+
| `services.[name].apis` | object | `{}` | API-specific cache configuration |
|
|
235
|
+
| `services.[name].apis[api].enabled` | boolean | `false` | Enable caching for this API |
|
|
236
|
+
| `services.[name].apis[api].ttl` | number | `defaultTTL` | Cache TTL for this specific API |
|
|
237
|
+
|
|
238
|
+
**Response Headers:**
|
|
239
|
+
- `X-Cache: HIT` - Response served from cache
|
|
240
|
+
- `X-Cache: MISS` - Response fetched from backend
|
|
241
|
+
- `X-Cache-Age: <seconds>` - Time since cached (on HIT)
|
|
242
|
+
|
|
243
|
+
**Notes:**
|
|
244
|
+
- Only GET requests are cached
|
|
245
|
+
- Only 2xx responses are cached
|
|
246
|
+
- Cache key includes tenant ID, service name, path, and query hash
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 6. Multi-Tenant IP Whitelist
|
|
126
251
|
|
|
127
252
|
**Path:** `registry.custom.gateway.value.mt.whitelist`
|
|
128
253
|
|
|
@@ -150,7 +275,7 @@ Allows specific IP ranges to bypass ACL and/or OAuth checks.
|
|
|
150
275
|
|
|
151
276
|
---
|
|
152
277
|
|
|
153
|
-
##
|
|
278
|
+
## 7. User Activity Tracking (Last Seen)
|
|
154
279
|
|
|
155
280
|
**Path:** `registry.custom.gateway.value.lastSeen`
|
|
156
281
|
|
|
@@ -180,7 +305,7 @@ Tracks user activity by notifying a service (typically URAC) of user access.
|
|
|
180
305
|
|
|
181
306
|
---
|
|
182
307
|
|
|
183
|
-
##
|
|
308
|
+
## 8. Request Monitoring
|
|
184
309
|
|
|
185
310
|
**Path:** `registry.custom.gateway.value.gotoService.monitor`
|
|
186
311
|
|
|
@@ -208,7 +333,7 @@ Controls which services are monitored for metrics collection.
|
|
|
208
333
|
|
|
209
334
|
---
|
|
210
335
|
|
|
211
|
-
##
|
|
336
|
+
## 9. Request Timeout Renewal
|
|
212
337
|
|
|
213
338
|
**Path:** `registry.custom.gateway.value.gotoService.renewReqMonitorOff`
|
|
214
339
|
|
|
@@ -230,7 +355,7 @@ Disables the heartbeat renewal mechanism for long-running requests.
|
|
|
230
355
|
|
|
231
356
|
---
|
|
232
357
|
|
|
233
|
-
##
|
|
358
|
+
## 10. OAuth Roaming (Cross-Environment)
|
|
234
359
|
|
|
235
360
|
**Path:** `registry.custom.oauth.value.roaming`
|
|
236
361
|
|
|
@@ -260,7 +385,7 @@ Enables cross-environment access for specific services with IP-based whitelistin
|
|
|
260
385
|
|
|
261
386
|
---
|
|
262
387
|
|
|
263
|
-
##
|
|
388
|
+
## 11. PIN Login Wrapper
|
|
264
389
|
|
|
265
390
|
**Path:** `registry.custom.oauth.value.pinWrapper`
|
|
266
391
|
|
|
@@ -284,7 +409,7 @@ Defines a custom PIN-based login endpoint that bypasses standard OAuth flow.
|
|
|
284
409
|
|
|
285
410
|
---
|
|
286
411
|
|
|
287
|
-
##
|
|
412
|
+
## 12. PIN Login API Whitelist
|
|
288
413
|
|
|
289
414
|
**Path:** `registry.custom.oauth.value.pinWhitelist`
|
|
290
415
|
|
|
@@ -359,6 +484,29 @@ Whitelists specific APIs that can be accessed when a user is PIN-locked (during
|
|
|
359
484
|
}
|
|
360
485
|
}
|
|
361
486
|
},
|
|
487
|
+
"idempotency": {
|
|
488
|
+
"model": "mongo",
|
|
489
|
+
"services": {
|
|
490
|
+
"payment": {
|
|
491
|
+
"enabled": true,
|
|
492
|
+
"ttl": 120000,
|
|
493
|
+
"apis": ["POST /charge", "POST /refund"]
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
"cache": {
|
|
498
|
+
"model": "mongo",
|
|
499
|
+
"defaultTTL": 300000,
|
|
500
|
+
"services": {
|
|
501
|
+
"catalog": {
|
|
502
|
+
"enabled": true,
|
|
503
|
+
"apis": {
|
|
504
|
+
"GET /products": { "enabled": true, "ttl": 600000 },
|
|
505
|
+
"GET /categories": { "enabled": true, "ttl": 3600000 }
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
},
|
|
362
510
|
"lastSeen": {
|
|
363
511
|
"active": true,
|
|
364
512
|
"serviceName": "urac",
|
|
@@ -417,5 +565,7 @@ Custom registry configurations are processed in this order:
|
|
|
417
565
|
| 4 | gotoService/preRedirect | `gotoService.renewReqMonitorOff` |
|
|
418
566
|
| 5 | gotoService/redirectToService | `gotoService.monitor` |
|
|
419
567
|
| 6 | mt (security checks) | `mt.whitelist`, `oauth.value.pinWrapper`, `oauth.value.pinWhitelist` |
|
|
420
|
-
| 7 |
|
|
421
|
-
| 8 |
|
|
568
|
+
| 7 | idempotency | `idempotency.model`, `idempotency.services.[name]` |
|
|
569
|
+
| 8 | traffic | `traffic.model`, `traffic.throttling` |
|
|
570
|
+
| 9 | cache | `cache.model`, `cache.defaultTTL`, `cache.services.[name]` |
|
|
571
|
+
| 10 | lastSeen | `lastSeen` |
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Cache Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/cache/index.js`
|
|
4
|
+
|
|
5
|
+
**Order:** 19 (after Traffic middleware)
|
|
6
|
+
|
|
7
|
+
The Cache middleware provides response caching for GET APIs with per-API TTL configuration.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
- Caches GET API responses to reduce backend load
|
|
12
|
+
- Supports per-API TTL configuration
|
|
13
|
+
- Provides cache hit/miss headers for debugging
|
|
14
|
+
- Supports memory and MongoDB storage backends
|
|
15
|
+
|
|
16
|
+
## Flow
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Incoming Request
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
┌─────────────────────────┐
|
|
23
|
+
│ Check Method │ GET request?
|
|
24
|
+
└────────┬────────────────┘
|
|
25
|
+
│
|
|
26
|
+
├─── Not GET ──▶ next()
|
|
27
|
+
│
|
|
28
|
+
▼
|
|
29
|
+
┌─────────────────────────┐
|
|
30
|
+
│ Check Configuration │ Service enabled? API matches?
|
|
31
|
+
└────────┬────────────────┘
|
|
32
|
+
│
|
|
33
|
+
├─── Not configured ──▶ next()
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
┌─────────────────────────┐
|
|
37
|
+
│ Generate Cache Key │ tenant:service:path:queryHash
|
|
38
|
+
└────────┬────────────────┘
|
|
39
|
+
│
|
|
40
|
+
▼
|
|
41
|
+
┌─────────────────────────┐
|
|
42
|
+
│ Lookup Cache │
|
|
43
|
+
└────────┬────────────────┘
|
|
44
|
+
│
|
|
45
|
+
├─── HIT ──▶ Return cached response (X-Cache: HIT)
|
|
46
|
+
│
|
|
47
|
+
└─── MISS ──▶ Execute → Cache response → Return (X-Cache: MISS)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Configuration
|
|
51
|
+
|
|
52
|
+
**Path:** `registry.custom.gateway.value.cache`
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
{
|
|
56
|
+
"cache": {
|
|
57
|
+
"model": "memory", // Storage: "memory" or "mongo"
|
|
58
|
+
"defaultTTL": 300000, // Default TTL: 5 minutes
|
|
59
|
+
"services": { // Service configurations
|
|
60
|
+
"av": { // Service name
|
|
61
|
+
"enabled": true, // Enable caching for this service
|
|
62
|
+
"apis": {
|
|
63
|
+
"GET /calls": {
|
|
64
|
+
"enabled": true,
|
|
65
|
+
"ttl": 30000 // 30 seconds
|
|
66
|
+
},
|
|
67
|
+
"GET /call/:id": {
|
|
68
|
+
"enabled": true,
|
|
69
|
+
"ttl": 60000 // 60 seconds
|
|
70
|
+
},
|
|
71
|
+
"GET /users": {
|
|
72
|
+
"enabled": true
|
|
73
|
+
// Uses defaultTTL (300000ms)
|
|
74
|
+
},
|
|
75
|
+
"GET /profile": {
|
|
76
|
+
"enabled": true,
|
|
77
|
+
"scope": "tenant_user" // Cache per tenant + logged-in user
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"catalog": {
|
|
82
|
+
"enabled": true,
|
|
83
|
+
"apis": {
|
|
84
|
+
"GET /products": {
|
|
85
|
+
"enabled": true,
|
|
86
|
+
"ttl": 600000 // 10 minutes
|
|
87
|
+
},
|
|
88
|
+
"GET /categories": {
|
|
89
|
+
"enabled": true,
|
|
90
|
+
"ttl": 3600000 // 1 hour
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
| Field | Type | Default | Description |
|
|
100
|
+
|-------|------|---------|-------------|
|
|
101
|
+
| `model` | string | `"memory"` | Storage backend: `"memory"` or `"mongo"` |
|
|
102
|
+
| `defaultTTL` | number | `300000` | Default cache TTL in milliseconds (5 min) |
|
|
103
|
+
| `services.[name].enabled` | boolean | `false` | Enable caching for this service |
|
|
104
|
+
| `services.[name].apis` | object | `{}` | API-specific cache configuration |
|
|
105
|
+
| `services.[name].apis[api].enabled` | boolean | `false` | Enable caching for this API |
|
|
106
|
+
| `services.[name].apis[api].ttl` | number | `defaultTTL` | Cache TTL for this API |
|
|
107
|
+
| `services.[name].apis[api].scope` | string | inferred | Cache scope: `"tenant"` or `"tenant_user"`. Defaults to `"tenant"` for public APIs and `"tenant_user"` for private APIs. |
|
|
108
|
+
|
|
109
|
+
## Caching Scope (Public vs Private APIs)
|
|
110
|
+
|
|
111
|
+
The cache key dimension depends on whether the API is **public** (no `access_token` required) or **private** (requires an `access_token`):
|
|
112
|
+
|
|
113
|
+
- **Public API** → the response is the same for the whole tenant, so it is cached per **tenant** (`scope: "tenant"`). The cache key contains the tenant id only.
|
|
114
|
+
- **Private API** → the response can differ per logged-in user, so it is cached per **tenant + user** (`scope: "tenant_user"`). The cache key also includes the user id, preventing one user from receiving another user's cached response.
|
|
115
|
+
|
|
116
|
+
The gateway determines public vs private automatically from `req.soajs.controller.serviceParams.isAPIPublic` and resolves the default scope accordingly. You can override the scope per API with the `scope` field.
|
|
117
|
+
|
|
118
|
+
| Scope | Cache key dimension | Default for |
|
|
119
|
+
|-------|---------------------|-------------|
|
|
120
|
+
| `tenant` | tenant id | Public APIs |
|
|
121
|
+
| `tenant_user` | tenant id + user id | Private APIs |
|
|
122
|
+
|
|
123
|
+
### Safety Behavior
|
|
124
|
+
|
|
125
|
+
If an API resolves to `tenant_user` scope but **no logged-in user can be resolved** (no URAC user on the request), the response is **not cached**. This prevents a user-scoped entry from being stored without a user identity and served to the wrong user. A misconfiguration therefore causes a cache miss, never a data leak.
|
|
126
|
+
|
|
127
|
+
An unrecognized `scope` value is ignored (with a warning) and falls back to the inferred default.
|
|
128
|
+
|
|
129
|
+
## API Pattern Matching
|
|
130
|
+
|
|
131
|
+
APIs are matched using `GET /path` format with support for path parameters:
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
"apis": {
|
|
135
|
+
"GET /users": { ... }, // Exact match
|
|
136
|
+
"GET /users/:id": { ... }, // :id matches any segment
|
|
137
|
+
"GET /users/:userId/posts/:postId": { ... } // Multiple params
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Cache Key Structure
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
// Public API (scope: "tenant")
|
|
145
|
+
{
|
|
146
|
+
"l1": "tenant_id",
|
|
147
|
+
"l2": "serviceName:GET:/path:queryHash"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Private API (scope: "tenant_user")
|
|
151
|
+
{
|
|
152
|
+
"l1": "tenant_id",
|
|
153
|
+
"l2": "serviceName:GET:/path:queryHash:u:user_id"
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- **tenant_id**: Isolates cache per tenant
|
|
158
|
+
- **serviceName**: The target service name
|
|
159
|
+
- **path**: The API path
|
|
160
|
+
- **queryHash**: MD5 hash of sorted query parameters
|
|
161
|
+
- **user_id**: The logged-in user id (only for `tenant_user` scope), isolating cache per user within the tenant
|
|
162
|
+
|
|
163
|
+
### Query Parameter Handling
|
|
164
|
+
|
|
165
|
+
Query parameters are included in the cache key via MD5 hash:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
GET /users?page=1&limit=10 → key includes hash of {"limit":"10","page":"1"}
|
|
169
|
+
GET /users?limit=10&page=1 → same hash (sorted)
|
|
170
|
+
GET /users → different key (no query hash)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Storage Backends
|
|
174
|
+
|
|
175
|
+
### Memory (Default)
|
|
176
|
+
|
|
177
|
+
- Fast, in-process storage
|
|
178
|
+
- Lost on restart
|
|
179
|
+
- Good for single-instance deployments
|
|
180
|
+
- Automatic cleanup of expired entries
|
|
181
|
+
|
|
182
|
+
### MongoDB
|
|
183
|
+
|
|
184
|
+
- Persistent storage
|
|
185
|
+
- Shared across instances
|
|
186
|
+
- Required for multi-instance deployments
|
|
187
|
+
- Uses TTL index for automatic expiration
|
|
188
|
+
|
|
189
|
+
## Response Headers
|
|
190
|
+
|
|
191
|
+
| Header | Description |
|
|
192
|
+
|--------|-------------|
|
|
193
|
+
| `X-Cache` | `HIT` or `MISS` indicating cache status |
|
|
194
|
+
| `X-Cache-Age` | Seconds since response was cached (on HIT) |
|
|
195
|
+
|
|
196
|
+
### Cache HIT
|
|
197
|
+
|
|
198
|
+
```http
|
|
199
|
+
HTTP/1.1 200 OK
|
|
200
|
+
X-Cache: HIT
|
|
201
|
+
X-Cache-Age: 15
|
|
202
|
+
Content-Type: application/json
|
|
203
|
+
|
|
204
|
+
{"data": [...]}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Cache MISS
|
|
208
|
+
|
|
209
|
+
```http
|
|
210
|
+
HTTP/1.1 200 OK
|
|
211
|
+
X-Cache: MISS
|
|
212
|
+
Content-Type: application/json
|
|
213
|
+
|
|
214
|
+
{"data": [...]}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Caching Behavior
|
|
218
|
+
|
|
219
|
+
### What Gets Cached
|
|
220
|
+
|
|
221
|
+
- Only successful responses (HTTP 2xx)
|
|
222
|
+
- Response status code
|
|
223
|
+
- Response headers
|
|
224
|
+
- Response body
|
|
225
|
+
|
|
226
|
+
### What Doesn't Get Cached
|
|
227
|
+
|
|
228
|
+
- Non-GET requests
|
|
229
|
+
- Error responses (4xx, 5xx)
|
|
230
|
+
- APIs not configured for caching
|
|
231
|
+
|
|
232
|
+
## Usage Notes
|
|
233
|
+
|
|
234
|
+
- Only GET requests are cached
|
|
235
|
+
- Cache is tenant-isolated; private APIs are additionally user-isolated (`tenant_user` scope)
|
|
236
|
+
- Public APIs default to `tenant` scope, private APIs default to `tenant_user` scope
|
|
237
|
+
- Private (`tenant_user`) requests without a resolved user are not cached (safety)
|
|
238
|
+
- Query parameters affect cache key
|
|
239
|
+
- Only 2xx responses are cached
|
|
240
|
+
- Headers like `X-Cache` are not stored in cache
|
|
241
|
+
- MongoDB backend required for horizontal scaling
|
|
242
|
+
- Consider TTL based on data freshness requirements
|
|
243
|
+
|
|
244
|
+
## Example Scenarios
|
|
245
|
+
|
|
246
|
+
### Static Data (Long TTL)
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
"GET /catalog/categories": {
|
|
250
|
+
"enabled": true,
|
|
251
|
+
"ttl": 3600000 // 1 hour - categories rarely change
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Dynamic Data (Short TTL)
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
"GET /av/calls": {
|
|
259
|
+
"enabled": true,
|
|
260
|
+
"ttl": 5000 // 5 seconds - frequently updated
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### User-Specific Data (Private API)
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
// Private API: cache key includes tenant ID AND user ID,
|
|
268
|
+
// so each user within a tenant has a separate cache entry.
|
|
269
|
+
// "tenant_user" is the default scope for private APIs, shown here explicitly.
|
|
270
|
+
"GET /users/profile": {
|
|
271
|
+
"enabled": true,
|
|
272
|
+
"ttl": 60000, // 1 minute
|
|
273
|
+
"scope": "tenant_user"
|
|
274
|
+
}
|
|
275
|
+
```
|