0
# Response and Request Models
1
2
Response and request models provide cached versions of HTTP requests and responses that maintain compatibility with the standard `requests` library while adding cache-specific metadata and functionality. These models handle serialization, deserialization, and provide cache status information.
3
4
## Capabilities
5
6
### Cached Response Model
7
8
The main response object returned by cached requests, providing full compatibility with `requests.Response` while adding cache-specific properties and methods.
9
10
```python { .api }
11
class CachedResponse:
12
"""
13
Cached response object that emulates requests.Response.
14
15
Provides all standard Response properties and methods plus
16
cache-specific functionality and metadata.
17
"""
18
19
def __init__(
20
self,
21
url: str = '',
22
status_code: int = 200,
23
reason: str = 'OK',
24
headers: Optional[Mapping[str, str]] = None,
25
content: bytes = b'',
26
encoding: Optional[str] = None,
27
history: Optional[List] = None,
28
request: Optional[AnyRequest] = None,
29
cookies: Optional[RequestsCookieJar] = None,
30
elapsed: Optional[timedelta] = None,
31
expires: Optional[datetime] = None,
32
**kwargs
33
):
34
"""
35
Create cached response object.
36
37
Parameters mirror requests.Response constructor plus:
38
- expires: When this cached response expires
39
"""
40
41
# Cache-specific properties
42
@property
43
def from_cache(self) -> bool:
44
"""True if response was served from cache, False if fresh."""
45
46
@property
47
def is_expired(self) -> bool:
48
"""True if cached response has expired."""
49
50
@property
51
def expires_delta(self) -> Optional[timedelta]:
52
"""Time until expiration (positive) or since expiration (negative)."""
53
54
@property
55
def expires_unix(self) -> Optional[float]:
56
"""Expiration time as Unix timestamp."""
57
58
@property
59
def size(self) -> int:
60
"""Size of cached response in bytes."""
61
62
# Cache management methods
63
def is_older_than(self, time: ExpirationTime) -> bool:
64
"""
65
Check if response is older than specified time.
66
67
Parameters:
68
- time: Time threshold in various formats (int, timedelta, datetime, str)
69
70
Returns:
71
True if response age exceeds threshold
72
"""
73
74
def reset_expiration(self, expire_after: ExpirationTime = None) -> None:
75
"""
76
Reset expiration time for cached response.
77
78
Parameters:
79
- expire_after: New expiration time (None for no expiration)
80
"""
81
82
# Standard requests.Response interface
83
@property
84
def text(self) -> str:
85
"""Response body as text."""
86
87
@property
88
def content(self) -> bytes:
89
"""Response body as bytes."""
90
91
def json(self, **kwargs) -> Any:
92
"""Parse response body as JSON."""
93
94
def iter_content(self, chunk_size: int = 1) -> Iterator[bytes]:
95
"""Iterate over response content in chunks."""
96
97
def iter_lines(self, **kwargs) -> Iterator[str]:
98
"""Iterate over response content line by line."""
99
100
def raise_for_status(self) -> None:
101
"""Raise HTTPError for bad status codes."""
102
103
# Standard response attributes
104
status_code: int
105
reason: str
106
url: str
107
headers: CaseInsensitiveDict
108
cookies: RequestsCookieJar
109
history: List
110
request: AnyRequest
111
elapsed: timedelta
112
encoding: Optional[str]
113
apparent_encoding: str
114
ok: bool
115
```
116
117
#### Usage Examples
118
119
Basic cached response usage:
120
121
```python
122
from requests_cache import CachedSession
123
124
session = CachedSession('demo_cache', expire_after=3600)
125
126
# First request - fetched from server
127
response = session.get('https://httpbin.org/json')
128
print(f"From cache: {response.from_cache}") # False
129
print(f"Status: {response.status_code}") # 200
130
print(f"Size: {response.size} bytes")
131
132
# Second request - served from cache
133
response = session.get('https://httpbin.org/json')
134
print(f"From cache: {response.from_cache}") # True
135
print(f"Expires in: {response.expires_delta}")
136
137
# Check expiration status
138
if not response.is_expired:
139
data = response.json()
140
print("Using cached data:", data)
141
142
# Reset expiration
143
response.reset_expiration(expire_after=7200) # 2 hours from now
144
```
145
146
Cache metadata inspection:
147
148
```python
149
import requests_cache
150
from datetime import datetime, timedelta
151
152
session = requests_cache.CachedSession('cache')
153
154
response = session.get('https://api.example.com/data')
155
156
# Cache status
157
print(f"From cache: {response.from_cache}")
158
print(f"Expired: {response.is_expired}")
159
print(f"Size: {response.size} bytes")
160
161
# Expiration info
162
if response.expires_delta:
163
if response.expires_delta.total_seconds() > 0:
164
print(f"Expires in: {response.expires_delta}")
165
else:
166
print(f"Expired {abs(response.expires_delta)} ago")
167
168
# Age checking
169
if response.is_older_than('1 hour'):
170
print("Response is older than 1 hour")
171
172
if response.is_older_than(timedelta(minutes=30)):
173
print("Response is older than 30 minutes")
174
```
175
176
### Original Response Wrapper
177
178
Wrapper for non-cached responses that provides cache-related properties for consistency.
179
180
```python { .api }
181
class OriginalResponse:
182
"""
183
Wrapper for requests.Response that adds cache-related properties.
184
185
Used for responses that bypass caching or are fetched fresh
186
from the server.
187
"""
188
189
@classmethod
190
def wrap_response(
191
cls,
192
response: Response,
193
actions: CacheActions
194
) -> 'OriginalResponse':
195
"""
196
Wrap a requests.Response with cache metadata.
197
198
Parameters:
199
- response: Original requests.Response
200
- actions: Cache actions that determined response handling
201
202
Returns:
203
OriginalResponse with cache properties
204
"""
205
206
@property
207
def from_cache(self) -> bool:
208
"""Always False for original responses."""
209
210
# Delegates all other attributes to wrapped response
211
```
212
213
### Cached Request Model
214
215
Cached version of HTTP requests that can be serialized and stored with responses.
216
217
```python { .api }
218
class CachedRequest:
219
"""
220
Serializable request object that emulates requests.PreparedRequest.
221
222
Stores request data alongside cached responses for cache key
223
generation and request matching.
224
"""
225
226
def __init__(
227
self,
228
method: Optional[str] = None,
229
url: Optional[str] = None,
230
headers: Optional[CaseInsensitiveDict] = None,
231
body: Optional[bytes] = None,
232
**kwargs
233
):
234
"""
235
Create cached request object.
236
237
Parameters mirror requests.PreparedRequest constructor.
238
"""
239
240
def copy(self) -> 'CachedRequest':
241
"""Create a copy of the cached request."""
242
243
# Standard PreparedRequest interface
244
method: Optional[str]
245
url: Optional[str]
246
headers: CaseInsensitiveDict
247
body: Optional[bytes]
248
hooks: Dict[str, List]
249
```
250
251
### HTTP Response Model
252
253
Low-level cached HTTP response for urllib3 compatibility.
254
255
```python { .api }
256
class CachedHTTPResponse:
257
"""
258
Cached HTTP response that provides urllib3.HTTPResponse compatibility.
259
260
Used internally by the caching system to maintain compatibility
261
with the requests library's response processing pipeline.
262
"""
263
264
def __init__(
265
self,
266
body: bytes = b'',
267
headers: Optional[Mapping[str, str]] = None,
268
status: int = 200,
269
reason: Optional[str] = None,
270
version: int = 11,
271
**kwargs
272
):
273
"""Create cached HTTP response for urllib3 compatibility."""
274
275
def read(self, amt: Optional[int] = None) -> bytes:
276
"""Read response body."""
277
278
def stream(self, amt: int = 1024) -> Iterator[bytes]:
279
"""Stream response body in chunks."""
280
281
def close(self) -> None:
282
"""Close response (no-op for cached responses)."""
283
```
284
285
### Base Classes and Mixins
286
287
Foundation classes providing common functionality for all model objects.
288
289
```python { .api }
290
class RichMixin:
291
"""
292
Mixin providing rich repr formatting for model objects.
293
294
Adds pretty-printed string representations with syntax
295
highlighting when used in rich-enabled environments.
296
"""
297
298
def __rich_repr__(self):
299
"""Rich representation for pretty printing."""
300
301
def __repr__(self) -> str:
302
"""Standard string representation."""
303
```
304
305
## Type Aliases and Unions
306
307
```python { .api }
308
# Response type unions
309
AnyResponse = Union[OriginalResponse, CachedResponse]
310
"""Union type representing any response object (cached or original)."""
311
312
AnyRequest = Union[Request, PreparedRequest, CachedRequest]
313
"""Union type representing any request object."""
314
315
AnyPreparedRequest = Union[PreparedRequest, CachedRequest]
316
"""Union type for prepared request objects."""
317
318
# Content type for JSON-compatible data
319
DecodedContent = Union[str, bytes, int, float, bool, None, Dict, List]
320
"""JSON-compatible content types for serialization."""
321
```
322
323
## Response Lifecycle
324
325
Understanding how responses flow through the caching system:
326
327
1. **Request Creation**: User makes request through CachedSession
328
2. **Cache Lookup**: System checks for existing cached response
329
3. **Cache Hit**: Return CachedResponse with `from_cache=True`
330
4. **Cache Miss**: Make HTTP request, get standard Response
331
5. **Response Wrapping**: Wrap as OriginalResponse with `from_cache=False`
332
6. **Response Storage**: Serialize and store as CachedResponse for future use
333
334
```python
335
# Example showing response lifecycle
336
from requests_cache import CachedSession
337
338
session = CachedSession('demo')
339
340
# First request - cache miss
341
response1 = session.get('https://httpbin.org/json')
342
print(type(response1)) # <class 'OriginalResponse'>
343
print(response1.from_cache) # False
344
345
# Second request - cache hit
346
response2 = session.get('https://httpbin.org/json')
347
print(type(response2)) # <class 'CachedResponse'>
348
print(response2.from_cache) # True
349
350
# Both provide same interface
351
print(response1.json() == response2.json()) # True
352
```
353
354
## Serialization Integration
355
356
Response models integrate seamlessly with the serialization system:
357
358
```python
359
from requests_cache import CachedSession
360
361
# Different serializers handle response data differently
362
json_session = CachedSession('json_cache', serializer='json')
363
pickle_session = CachedSession('pickle_cache', serializer='pickle')
364
365
# All serializers preserve response properties and methods
366
response = json_session.get('https://httpbin.org/json')
367
print(f"From cache: {response.from_cache}")
368
print(f"Data: {response.json()}")
369
```