0
# HTTP Request Handling
1
2
The http module provides comprehensive HTTP functionality including individual request execution, batch processing, retry logic, authentication integration, and testing utilities.
3
4
## Capabilities
5
6
### Individual HTTP Requests
7
8
Execute individual HTTP requests with authentication, retry logic, and response processing.
9
10
```python { .api }
11
class HttpRequest:
12
"""Represents an HTTP request to be executed."""
13
14
def __init__(self, http, postproc, uri, method='GET', body=None,
15
headers=None, methodId=None, resumable=None):
16
"""
17
Initialize an HTTP request.
18
19
Args:
20
http (httplib2.Http): HTTP client to use for the request
21
postproc (callable): Function to process the response
22
uri (str): URI for the HTTP request
23
method (str): HTTP method ('GET', 'POST', 'PUT', 'DELETE', etc.)
24
body (str, optional): Request body content
25
headers (dict, optional): HTTP headers for the request
26
methodId (str, optional): API method identifier for logging
27
resumable (MediaUpload, optional): Resumable media upload
28
"""
29
30
def execute(self, http=None, num_retries=0):
31
"""
32
Execute the HTTP request.
33
34
Args:
35
http (httplib2.Http, optional): HTTP client to use (overrides default)
36
num_retries (int): Number of times to retry on recoverable errors
37
38
Returns:
39
object: Deserialized response content based on the response model
40
41
Raises:
42
HttpError: When the HTTP request fails with an error status
43
ResumableUploadError: When resumable upload fails
44
"""
45
46
def add_response_callback(self, cb):
47
"""
48
Add a callback function to process the HTTP response.
49
50
Args:
51
cb (callable): Callback function that takes (resp, content) arguments
52
"""
53
54
def to_json(self):
55
"""
56
Serialize the request to JSON for storage or transmission.
57
58
Returns:
59
str: JSON representation of the request
60
"""
61
62
@staticmethod
63
def from_json(s, http, postproc):
64
"""
65
Deserialize a request from JSON.
66
67
Args:
68
s (str): JSON string representing a request
69
http (httplib2.Http): HTTP client instance
70
postproc (callable): Response post-processing function
71
72
Returns:
73
HttpRequest: Reconstructed request object
74
"""
75
76
def next_chunk(self, http=None, num_retries=0):
77
"""
78
Download the next chunk of a resumable media upload.
79
80
Args:
81
http (httplib2.Http, optional): HTTP client to use
82
num_retries (int): Number of retry attempts
83
84
Returns:
85
tuple: (MediaUploadProgress or None, object or None) -
86
Progress status and response body (None until upload complete)
87
"""
88
89
@staticmethod
90
def null_postproc(resp, contents):
91
"""
92
Default post-processing function that returns response as-is.
93
94
Args:
95
resp: HTTP response object
96
contents: Response body content
97
98
Returns:
99
tuple: (resp, contents) unchanged
100
"""
101
```
102
103
### Batch HTTP Requests
104
105
Execute multiple HTTP requests efficiently in a single batch operation.
106
107
```python { .api }
108
class BatchHttpRequest:
109
"""Batch multiple HTTP requests for efficient execution."""
110
111
def __init__(self, callback=None, batch_uri=None):
112
"""
113
Initialize a batch HTTP request.
114
115
Args:
116
callback (callable, optional): Default callback for all requests
117
batch_uri (str, optional): Custom URI for batch endpoint
118
"""
119
120
def add(self, request, callback=None, request_id=None):
121
"""
122
Add a request to the batch.
123
124
Args:
125
request (HttpRequest): The request to add to the batch
126
callback (callable, optional): Callback for this specific request
127
request_id (str, optional): Unique identifier for this request
128
129
Raises:
130
BatchError: When the batch is full or request is invalid
131
"""
132
133
def execute(self, http=None, num_retries=0):
134
"""
135
Execute all requests in the batch.
136
137
Args:
138
http (httplib2.Http, optional): HTTP client to use
139
num_retries (int): Number of retry attempts for the batch
140
141
Raises:
142
BatchError: When batch execution fails
143
"""
144
```
145
146
### HTTP Constants
147
148
```python { .api }
149
DEFAULT_CHUNK_SIZE = 100 * 1024 * 1024 # 100MB default chunk size
150
MAX_URI_LENGTH = 2048 # Maximum URI length for GET requests
151
MAX_BATCH_LIMIT = 1000 # Maximum requests per batch
152
DEFAULT_HTTP_TIMEOUT_SEC = 60 # Default HTTP timeout in seconds
153
```
154
155
### Media Upload Progress
156
157
Progress tracking for resumable media uploads.
158
159
```python { .api }
160
class MediaUploadProgress:
161
"""Status of a resumable upload."""
162
163
def __init__(self, resumable_progress, total_size):
164
"""
165
Initialize upload progress.
166
167
Args:
168
resumable_progress (int): Bytes sent so far
169
total_size (int or None): Total bytes in complete upload, or None if unknown
170
"""
171
172
def progress(self):
173
"""
174
Get upload progress as a percentage.
175
176
Returns:
177
float: Percent of upload completed (0.0 if total size unknown)
178
"""
179
```
180
181
### Media Download Progress
182
183
Progress tracking for media downloads.
184
185
```python { .api }
186
class MediaDownloadProgress:
187
"""Status of a resumable download."""
188
189
def __init__(self, resumable_progress, total_size):
190
"""
191
Initialize download progress.
192
193
Args:
194
resumable_progress (int): Bytes received so far
195
total_size (int): Total bytes in complete download
196
"""
197
198
def progress(self):
199
"""
200
Get download progress as a percentage.
201
202
Returns:
203
float: Percent of download completed (0.0 if total size unknown)
204
"""
205
```
206
207
### HTTP Testing Utilities
208
209
Mock classes for testing HTTP requests and responses.
210
211
```python { .api }
212
class HttpMock:
213
"""Mock of httplib2.Http for testing."""
214
215
def __init__(self, filename=None, headers=None):
216
"""
217
Initialize HTTP mock.
218
219
Args:
220
filename (str, optional): Absolute path to response file
221
headers (dict, optional): Headers to return (default: {"status": "200"})
222
"""
223
224
def request(self, uri, method="GET", body=None, headers=None,
225
redirections=1, connection_type=None):
226
"""
227
Mock HTTP request.
228
229
Args:
230
uri (str): Request URI
231
method (str): HTTP method
232
body (str, optional): Request body
233
headers (dict, optional): Request headers
234
redirections (int): Number of redirections to follow
235
connection_type: Connection type
236
237
Returns:
238
tuple: (httplib2.Response, bytes or None) - mock response
239
"""
240
241
def close(self):
242
"""Close connections (compatibility method)."""
243
244
class HttpMockSequence:
245
"""Mock a sequence of HTTP responses for testing."""
246
247
def __init__(self, iterable):
248
"""
249
Initialize mock sequence.
250
251
Args:
252
iterable: Sequence of (headers, body) pairs for sequential responses
253
"""
254
255
def request(self, uri, method="GET", body=None, headers=None,
256
redirections=1, connection_type=None):
257
"""
258
Return sequential mock responses.
259
260
Returns:
261
tuple: (httplib2.Response, bytes) - next response in sequence
262
"""
263
```
264
265
### HTTP Utility Functions
266
267
Utility functions for HTTP client configuration and processing.
268
269
```python { .api }
270
def set_user_agent(http, user_agent):
271
"""
272
Set the user-agent header on every request.
273
274
Args:
275
http (httplib2.Http): HTTP client instance
276
user_agent (str): User-agent string
277
278
Returns:
279
httplib2.Http: Modified HTTP client with user-agent injection
280
"""
281
282
def tunnel_patch(http):
283
"""
284
Tunnel PATCH requests over POST for OAuth 1.0 compatibility.
285
286
Args:
287
http (httplib2.Http): HTTP client instance
288
289
Returns:
290
httplib2.Http: Modified HTTP client with PATCH tunneling
291
"""
292
293
def build_http():
294
"""
295
Build an httplib2.Http object with default timeout and redirect handling.
296
297
Returns:
298
httplib2.Http: HTTP client with default configuration
299
"""
300
```
301
302
## Usage Examples
303
304
### Basic Request Execution
305
306
```python
307
from googleapiclient import discovery
308
309
# Build service and create request
310
service = discovery.build('gmail', 'v1', credentials=credentials)
311
request = service.users().messages().list(userId='me', maxResults=10)
312
313
# Execute with retry
314
try:
315
response = request.execute(num_retries=3)
316
print(f"Found {len(response.get('messages', []))} messages")
317
except Exception as e:
318
print(f"Request failed: {e}")
319
```
320
321
### Request Serialization and Deserialization
322
323
```python
324
from googleapiclient import discovery
325
from googleapiclient.http import HttpRequest
326
import json
327
328
# Create and serialize request
329
service = discovery.build('gmail', 'v1', credentials=credentials)
330
request = service.users().messages().get(userId='me', id='message_id')
331
request_json = request.to_json()
332
333
# Store or transmit request_json...
334
335
# Recreate request from JSON
336
restored_request = HttpRequest.from_json(request_json)
337
response = restored_request.execute()
338
```
339
340
### Response Callbacks
341
342
```python
343
def response_callback(resp, content):
344
print(f"Response status: {resp.status}")
345
print(f"Response headers: {resp}")
346
print(f"Content length: {len(content) if content else 0}")
347
348
request = service.users().messages().list(userId='me')
349
request.add_response_callback(response_callback)
350
response = request.execute()
351
```
352
353
### Batch Request Processing
354
355
```python
356
from googleapiclient import http
357
358
def batch_callback(request_id, response, exception):
359
"""Handle individual batch request results."""
360
if exception is not None:
361
print(f'Request {request_id} failed: {exception}')
362
else:
363
print(f'Request {request_id} succeeded: {response}')
364
365
# Create batch request
366
batch = http.BatchHttpRequest(callback=batch_callback)
367
368
# Add multiple requests to batch
369
message_ids = ['msg1', 'msg2', 'msg3', 'msg4', 'msg5']
370
for i, msg_id in enumerate(message_ids):
371
request = service.users().messages().get(userId='me', id=msg_id)
372
batch.add(request, request_id=f'message_{i}')
373
374
# Execute all requests in batch
375
batch.execute()
376
```
377
378
### Batch with Custom Callbacks
379
380
```python
381
def process_message(request_id, response, exception):
382
if exception:
383
print(f"Failed to get message {request_id}: {exception}")
384
else:
385
subject = 'No subject'
386
for header in response.get('payload', {}).get('headers', []):
387
if header['name'] == 'Subject':
388
subject = header['value']
389
break
390
print(f"Message {request_id}: {subject}")
391
392
def process_label(request_id, response, exception):
393
if exception:
394
print(f"Failed to get label {request_id}: {exception}")
395
else:
396
print(f"Label {request_id}: {response.get('name', 'Unknown')}")
397
398
batch = http.BatchHttpRequest()
399
400
# Add requests with different callbacks
401
batch.add(
402
service.users().messages().get(userId='me', id='msg1'),
403
callback=process_message,
404
request_id='message_1'
405
)
406
batch.add(
407
service.users().labels().get(userId='me', id='INBOX'),
408
callback=process_label,
409
request_id='inbox_label'
410
)
411
412
batch.execute()
413
```
414
415
### Error Handling with Retries
416
417
```python
418
from googleapiclient.errors import HttpError
419
import time
420
421
def execute_with_backoff(request, max_retries=3):
422
"""Execute request with exponential backoff."""
423
for attempt in range(max_retries):
424
try:
425
return request.execute()
426
except HttpError as error:
427
if error.resp.status in [429, 500, 502, 503, 504]:
428
if attempt < max_retries - 1:
429
wait_time = (2 ** attempt) + (random.randint(0, 1000) / 1000)
430
time.sleep(wait_time)
431
continue
432
raise
433
434
# Use custom retry logic
435
request = service.users().messages().list(userId='me')
436
response = execute_with_backoff(request)
437
```
438
439
### Working with Large Result Sets
440
441
```python
442
def get_all_messages(service, user_id='me'):
443
"""Get all messages using pagination."""
444
messages = []
445
request = service.users().messages().list(userId=user_id)
446
447
while request is not None:
448
response = request.execute()
449
messages.extend(response.get('messages', []))
450
request = service.users().messages().list_next(request, response)
451
452
return messages
453
454
all_messages = get_all_messages(service)
455
print(f"Total messages: {len(all_messages)}")
456
```