0
# Data Models and Request Processing
1
2
The model module provides data models for handling different request and response formats including JSON, raw data, media, and protocol buffers. These models control how request parameters are serialized and how responses are processed.
3
4
## Capabilities
5
6
### Base Model Classes
7
8
Abstract base classes that define the model interface for all data formats.
9
10
```python { .api }
11
class Model:
12
"""Model base class.
13
14
All Model classes should implement this interface. The Model serializes and
15
de-serializes between a wire format such as JSON and a Python object representation.
16
"""
17
18
def request(self, headers, path_params, query_params, body_value):
19
"""
20
Updates the request with serialized body and appropriate headers.
21
22
Args:
23
headers (dict): HTTP headers dictionary to modify
24
path_params (dict): Parameters for URL path substitution
25
query_params (dict): Query string parameters
26
body_value (object): Request body data to serialize
27
28
Returns:
29
tuple: (headers, path_params, query, body) - processed request components
30
"""
31
32
def response(self, resp, content):
33
"""
34
Converts the HTTP response into a Python object.
35
36
Args:
37
resp (httplib2.Response): HTTP response object
38
content (bytes): Response body content
39
40
Returns:
41
object: Deserialized Python object representation
42
43
Raises:
44
googleapiclient.errors.HttpError: For non-2xx HTTP responses
45
"""
46
47
class BaseModel(Model):
48
"""Base model class.
49
50
Subclasses should provide implementations for the 'serialize' and 'deserialize'
51
methods, as well as values for the following class attributes:
52
- accept: HTTP Accept header value
53
- content_type: HTTP Content-type header value
54
- no_content_response: Value for 204 No Content responses
55
- alt_param: Value for "alt" query parameter
56
"""
57
58
accept = None
59
content_type = None
60
no_content_response = None
61
alt_param = None
62
63
def request(self, headers, path_params, query_params, body_value, api_version=None):
64
"""
65
Enhanced request method with API version support.
66
67
Args:
68
headers (dict): HTTP headers dictionary to modify
69
path_params (dict): Parameters for URL path substitution
70
query_params (dict): Query string parameters
71
body_value (object): Request body data to serialize
72
api_version (str, optional): API version for request metadata
73
74
Returns:
75
tuple: (headers, path_params, query, body) - processed request components
76
"""
77
78
def response(self, resp, content):
79
"""
80
Process HTTP response with error handling.
81
82
Args:
83
resp (httplib2.Response): HTTP response object
84
content (bytes): Response body content
85
86
Returns:
87
object: Deserialized response object
88
"""
89
90
def serialize(self, body_value):
91
"""
92
Serialize Python object to wire format.
93
94
Args:
95
body_value (object): Python object to serialize
96
97
Returns:
98
str or bytes: Serialized representation
99
"""
100
101
def deserialize(self, content):
102
"""
103
Deserialize wire format to Python object.
104
105
Args:
106
content (bytes): Serialized content to deserialize
107
108
Returns:
109
object: Deserialized Python object
110
"""
111
```
112
113
### JSON Data Model
114
115
Handle JSON request and response processing with optional data wrapping.
116
117
```python { .api }
118
class JsonModel(BaseModel):
119
"""Model for JSON request and response processing."""
120
121
def __init__(self, data_wrapper=False):
122
"""
123
Initialize JSON model.
124
125
Args:
126
data_wrapper (bool): Whether to wrap request data in a 'data' field
127
"""
128
129
def request(self, headers, path_params, query_params, body_value):
130
"""
131
Create a JSON request.
132
133
Args:
134
headers (dict): HTTP headers to modify
135
path_params (dict): Parameters for URL path substitution
136
query_params (dict): Query string parameters
137
body_value (object): Request body data to serialize
138
139
Returns:
140
tuple: (headers, path_params, query_params, body) - processed request components
141
"""
142
143
def response(self, resp, content):
144
"""
145
Process a JSON response.
146
147
Args:
148
resp (httplib2.Response): HTTP response object
149
content (bytes): Response body content
150
151
Returns:
152
object: Deserialized JSON response data
153
"""
154
```
155
156
### Raw Data Model
157
158
Handle raw binary request and response data without serialization.
159
160
```python { .api }
161
class RawModel(JsonModel):
162
"""Model for requests that don't return JSON.
163
164
Serializes and de-serializes between JSON and the Python object representation
165
of HTTP request, and returns the raw bytes of the response body.
166
"""
167
168
def request(self, headers, path_params, query_params, body_value):
169
"""
170
Create a raw data request.
171
172
Args:
173
headers (dict): HTTP headers to modify
174
path_params (dict): Parameters for URL path substitution
175
query_params (dict): Query string parameters
176
body_value (bytes or str): Raw request body data
177
178
Returns:
179
tuple: (headers, path_params, query_params, body) - processed request components
180
"""
181
182
def response(self, resp, content):
183
"""
184
Process a raw response.
185
186
Args:
187
resp (httplib2.Response): HTTP response object
188
content (bytes): Response body content
189
190
Returns:
191
bytes: Raw response content
192
"""
193
```
194
195
### Media Data Model
196
197
Handle media requests and responses for file uploads and downloads.
198
199
```python { .api }
200
class MediaModel(JsonModel):
201
"""Model for requests that return Media.
202
203
Serializes and de-serializes between JSON and the Python object representation
204
of HTTP request, and returns the raw bytes of the response body.
205
"""
206
207
def request(self, headers, path_params, query_params, body_value):
208
"""
209
Create a media request.
210
211
Args:
212
headers (dict): HTTP headers to modify
213
path_params (dict): Parameters for URL path substitution
214
query_params (dict): Query string parameters
215
body_value (MediaUpload): Media upload object
216
217
Returns:
218
tuple: (headers, path_params, query_params, body) - processed request components
219
"""
220
221
def response(self, resp, content):
222
"""
223
Process a media response.
224
225
Args:
226
resp (httplib2.Response): HTTP response object
227
content (bytes): Response body content
228
229
Returns:
230
object: Processed media response data
231
"""
232
```
233
234
### Protocol Buffer Model
235
236
Handle Protocol Buffer serialization and deserialization.
237
238
```python { .api }
239
class ProtocolBufferModel(BaseModel):
240
"""Model for protocol buffers.
241
242
Serializes and de-serializes the binary protocol buffer sent in the HTTP
243
request and response bodies.
244
"""
245
246
def __init__(self, protocol_buffer):
247
"""
248
Initialize Protocol Buffer model.
249
250
Args:
251
protocol_buffer: Protocol Buffer message class for serialization
252
"""
253
254
def request(self, headers, path_params, query_params, body_value):
255
"""
256
Create a Protocol Buffer request.
257
258
Args:
259
headers (dict): HTTP headers to modify
260
path_params (dict): Parameters for URL path substitution
261
query_params (dict): Query string parameters
262
body_value (Message): Protocol Buffer message to serialize
263
264
Returns:
265
tuple: (headers, path_params, query_params, body) - processed request components
266
"""
267
268
def response(self, resp, content):
269
"""
270
Process a Protocol Buffer response.
271
272
Args:
273
resp (httplib2.Response): HTTP response object
274
content (bytes): Response body content
275
276
Returns:
277
Message: Deserialized Protocol Buffer message
278
"""
279
```
280
281
### Request Processing Utilities
282
283
Utility functions for request body construction and parameter handling.
284
285
```python { .api }
286
def makepatch(original, modified):
287
"""
288
Create a patch object by comparing two resource states.
289
290
Some methods support PATCH, an efficient way to send updates to a resource.
291
This method allows the easy construction of patch bodies by looking at the
292
differences between a resource before and after it was modified.
293
294
Args:
295
original (object): The original deserialized resource
296
modified (object): The modified deserialized resource
297
298
Returns:
299
object: An object containing only the changes from original to modified
300
"""
301
302
# Module-level debugging flag
303
dump_request_response = False # Boolean flag for enabling request/response logging
304
```
305
306
## Usage Examples
307
308
### Custom JSON Model
309
310
```python
311
from googleapiclient import discovery
312
from googleapiclient.model import JsonModel
313
314
# Create service with custom JSON model
315
json_model = JsonModel(data_wrapper=True)
316
service = discovery.build(
317
'gmail',
318
'v1',
319
credentials=credentials,
320
model=json_model
321
)
322
323
# Requests will wrap data in 'data' field
324
# Responses will be processed as JSON
325
messages = service.users().messages().list(userId='me').execute()
326
```
327
328
### Raw Data Model
329
330
```python
331
from googleapiclient.model import RawModel
332
333
# Create service with raw model for binary data
334
raw_model = RawModel()
335
service = discovery.build(
336
'storage',
337
'v1',
338
credentials=credentials,
339
model=raw_model
340
)
341
342
# Responses will be returned as raw bytes
343
object_data = service.objects().get(
344
bucket='my-bucket',
345
object='my-file.bin'
346
).execute()
347
348
print(f"Downloaded {len(object_data)} bytes")
349
```
350
351
### Media Model Integration
352
353
```python
354
from googleapiclient.model import MediaModel
355
from googleapiclient.http import MediaFileUpload
356
357
# Create service with media model
358
media_model = MediaModel()
359
service = discovery.build(
360
'drive',
361
'v3',
362
credentials=credentials,
363
model=media_model
364
)
365
366
# Upload with media model handling
367
media = MediaFileUpload('document.pdf', mimetype='application/pdf')
368
file_metadata = {'name': 'uploaded-document.pdf'}
369
370
file = service.files().create(
371
body=file_metadata,
372
media_body=media
373
).execute()
374
```
375
376
### Protocol Buffer Model
377
378
```python
379
from googleapiclient.model import ProtocolBufferModel
380
import my_protobuf_pb2 # Your protocol buffer definitions
381
382
# Create service with protocol buffer model
383
pb_model = ProtocolBufferModel(my_protobuf_pb2.MyMessage)
384
service = discovery.build(
385
'my-api',
386
'v1',
387
credentials=credentials,
388
model=pb_model
389
)
390
391
# Create protocol buffer message
392
message = my_protobuf_pb2.MyMessage()
393
message.field1 = "value1"
394
message.field2 = 42
395
396
# Send protocol buffer request
397
response = service.my_resource().create(body=message).execute()
398
# Response will be deserialized protocol buffer
399
```
400
401
### Custom Request Body Processing
402
403
```python
404
from googleapiclient.model import makebody
405
406
# Custom request processing
407
def create_custom_request(service, resource_data):
408
headers = {'Content-Type': 'application/json'}
409
params = {'userId': 'me', 'format': 'json'}
410
411
# Method description from discovery document
412
method_desc = {
413
'parameters': {
414
'userId': {'location': 'path'},
415
'format': {'location': 'query'}
416
}
417
}
418
419
# Create request body
420
processed_headers, processed_body = makebody(
421
headers,
422
params,
423
resource_data,
424
method_desc
425
)
426
427
return processed_headers, processed_body
428
429
# Use custom processing
430
headers, body = create_custom_request(service, {'message': 'Hello World'})
431
```
432
433
### JSON Patch Creation
434
435
```python
436
from googleapiclient.model import makepatch
437
438
# Original and modified data
439
original_message = {
440
'subject': 'Original Subject',
441
'body': 'Original body text',
442
'labels': ['INBOX', 'UNREAD']
443
}
444
445
modified_message = {
446
'subject': 'Updated Subject',
447
'body': 'Original body text', # Unchanged
448
'labels': ['INBOX'] # Removed UNREAD
449
}
450
451
# Create patch
452
patch = makepatch(original_message, modified_message)
453
print(patch)
454
# Output: Patch operations representing the changes
455
456
# Use patch in API request
457
service.users().messages().modify(
458
userId='me',
459
id='message_id',
460
body=patch
461
).execute()
462
```
463
464
### Model Selection Based on Content Type
465
466
```python
467
from googleapiclient.model import JsonModel, RawModel, MediaModel
468
469
def get_model_for_content_type(content_type):
470
"""Select appropriate model based on content type."""
471
472
if content_type.startswith('application/json'):
473
return JsonModel()
474
elif content_type.startswith('image/') or content_type.startswith('video/'):
475
return MediaModel()
476
else:
477
return RawModel()
478
479
# Dynamic model selection
480
content_type = 'application/json'
481
model = get_model_for_content_type(content_type)
482
483
service = discovery.build(
484
'my-api',
485
'v1',
486
credentials=credentials,
487
model=model
488
)
489
```
490
491
### Request and Response Interception
492
493
```python
494
from googleapiclient.model import JsonModel
495
496
class LoggingJsonModel(JsonModel):
497
"""JSON model with request/response logging."""
498
499
def request(self, headers, path_params, query_params, body_value):
500
print(f"Request body: {body_value}")
501
return super().request(headers, path_params, query_params, body_value)
502
503
def response(self, resp, content):
504
print(f"Response status: {resp.status}")
505
result = super().response(resp, content)
506
print(f"Response data: {result}")
507
return result
508
509
# Use logging model
510
logging_model = LoggingJsonModel()
511
service = discovery.build(
512
'gmail',
513
'v1',
514
credentials=credentials,
515
model=logging_model
516
)
517
518
# All requests and responses will be logged
519
messages = service.users().messages().list(userId='me').execute()
520
```