or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdchannel.mddiscovery.mderrors.mdhttp.mdindex.mdmedia.mdmimeparse.mdmodel.mdschema.mdtesting.md

schema.mddocs/

0

# Schema Validation and Processing

1

2

The schema module provides functionality for validating API request parameters and response data against JSON schemas defined in discovery documents. It enables pretty-printing of schema definitions and validation of data structures.

3

4

## Capabilities

5

6

### Schema Management

7

8

Manage and validate data against JSON schemas from API discovery documents.

9

10

```python { .api }

11

class Schemas:

12

"""Manage JSON schemas for API validation and documentation."""

13

14

def __init__(self, discovery_doc):

15

"""

16

Initialize schema manager with discovery document.

17

18

Args:

19

discovery_doc (dict): Complete API discovery document containing schemas

20

"""

21

22

def get(self, name, default=None):

23

"""

24

Get a schema definition by name.

25

26

Args:

27

name (str): Name of the schema to retrieve

28

default (object, optional): Default value if schema not found

29

30

Returns:

31

dict: Schema definition, or default if not found

32

"""

33

34

def prettyPrintByName(self, name):

35

"""

36

Pretty print a schema definition by name.

37

38

Args:

39

name (str): Name of the schema to pretty print

40

41

Returns:

42

str: Formatted string representation of the schema

43

"""

44

45

def prettyPrintSchema(self, val):

46

"""

47

Pretty print a schema definition.

48

49

Args:

50

val (dict): Schema definition to pretty print

51

52

Returns:

53

str: Formatted string representation of the schema

54

"""

55

56

def _prettyPrintByName(self, name, seen):

57

"""

58

Internal method for pretty printing schema by name with circular reference tracking.

59

60

Args:

61

name (str): Schema name to print

62

seen (set): Set of already processed schemas to prevent infinite recursion

63

64

Returns:

65

str: Formatted schema representation

66

"""

67

68

def _prettyPrintSchema(self, val, seen):

69

"""

70

Internal method for pretty printing schema with circular reference tracking.

71

72

Args:

73

val (dict): Schema definition to print

74

seen (set): Set of already processed schemas to prevent infinite recursion

75

76

Returns:

77

str: Formatted schema representation

78

"""

79

```

80

81

## Usage Examples

82

83

### Basic Schema Operations

84

85

```python

86

from googleapiclient import discovery

87

from googleapiclient.schema import Schemas

88

89

# Build service and get discovery document

90

service = discovery.build('gmail', 'v1', credentials=credentials)

91

discovery_doc = service._rootDesc # Access discovery document

92

93

# Create schema manager

94

schemas = Schemas(discovery_doc)

95

96

# Get a specific schema

97

message_schema = schemas.get('Message')

98

if message_schema:

99

print("Message schema found:")

100

print(schemas.prettyPrintSchema(message_schema))

101

else:

102

print("Message schema not found")

103

104

# Pretty print schema by name

105

thread_schema_str = schemas.prettyPrintByName('Thread')

106

print("Thread schema:")

107

print(thread_schema_str)

108

```

109

110

### Schema Exploration

111

112

```python

113

from googleapiclient.schema import Schemas

114

import json

115

116

def explore_api_schemas(service_name, version):

117

"""Explore all schemas in an API."""

118

119

service = discovery.build(service_name, version, credentials=credentials)

120

discovery_doc = service._rootDesc

121

122

schemas = Schemas(discovery_doc)

123

124

# Get all available schemas

125

schema_names = discovery_doc.get('schemas', {}).keys()

126

127

print(f"Available schemas in {service_name} {version}:")

128

for name in sorted(schema_names):

129

schema = schemas.get(name)

130

if schema:

131

print(f"\n{name}:")

132

print(schemas.prettyPrintByName(name))

133

print("-" * 50)

134

135

# Explore Gmail API schemas

136

explore_api_schemas('gmail', 'v1')

137

```

138

139

### Schema-Based Validation

140

141

```python

142

from googleapiclient.schema import Schemas

143

import jsonschema

144

145

class SchemaValidator:

146

"""Validate data against API schemas."""

147

148

def __init__(self, discovery_doc):

149

self.schemas = Schemas(discovery_doc)

150

self.discovery_doc = discovery_doc

151

152

def validate_data(self, schema_name, data):

153

"""

154

Validate data against a named schema.

155

156

Args:

157

schema_name (str): Name of the schema to validate against

158

data (dict): Data to validate

159

160

Returns:

161

tuple: (is_valid, errors) - validation result and error list

162

"""

163

schema_def = self.schemas.get(schema_name)

164

if not schema_def:

165

return False, [f"Schema '{schema_name}' not found"]

166

167

try:

168

# Convert Google API schema to JSON Schema format

169

json_schema = self._convert_to_json_schema(schema_def)

170

jsonschema.validate(data, json_schema)

171

return True, []

172

except jsonschema.ValidationError as e:

173

return False, [str(e)]

174

except Exception as e:

175

return False, [f"Validation error: {e}"]

176

177

def _convert_to_json_schema(self, api_schema):

178

"""Convert Google API schema to JSON Schema format."""

179

# This is a simplified conversion - real implementation would be more complex

180

json_schema = {

181

"type": "object",

182

"properties": {},

183

"required": []

184

}

185

186

if "properties" in api_schema:

187

for prop_name, prop_def in api_schema["properties"].items():

188

json_schema["properties"][prop_name] = self._convert_property(prop_def)

189

if prop_def.get("required", False):

190

json_schema["required"].append(prop_name)

191

192

return json_schema

193

194

def _convert_property(self, prop_def):

195

"""Convert a single property definition."""

196

prop_schema = {}

197

198

# Map Google API types to JSON Schema types

199

type_mapping = {

200

"string": "string",

201

"integer": "integer",

202

"number": "number",

203

"boolean": "boolean",

204

"array": "array",

205

"object": "object"

206

}

207

208

api_type = prop_def.get("type", "string")

209

prop_schema["type"] = type_mapping.get(api_type, "string")

210

211

if "description" in prop_def:

212

prop_schema["description"] = prop_def["description"]

213

214

if api_type == "array" and "items" in prop_def:

215

prop_schema["items"] = self._convert_property(prop_def["items"])

216

217

return prop_schema

218

219

# Usage

220

service = discovery.build('gmail', 'v1', credentials=credentials)

221

validator = SchemaValidator(service._rootDesc)

222

223

# Validate message data

224

message_data = {

225

"id": "message123",

226

"threadId": "thread456",

227

"labelIds": ["INBOX", "UNREAD"],

228

"snippet": "This is a test message..."

229

}

230

231

is_valid, errors = validator.validate_data('Message', message_data)

232

if is_valid:

233

print("Message data is valid")

234

else:

235

print("Validation errors:")

236

for error in errors:

237

print(f" - {error}")

238

```

239

240

### Schema Documentation Generator

241

242

```python

243

from googleapiclient.schema import Schemas

244

245

class SchemaDocumentationGenerator:

246

"""Generate documentation from API schemas."""

247

248

def __init__(self, discovery_doc):

249

self.schemas = Schemas(discovery_doc)

250

self.discovery_doc = discovery_doc

251

252

def generate_markdown_docs(self, output_file):

253

"""Generate Markdown documentation for all schemas."""

254

255

with open(output_file, 'w') as f:

256

f.write("# API Schema Documentation\n\n")

257

258

schema_names = self.discovery_doc.get('schemas', {}).keys()

259

260

for name in sorted(schema_names):

261

f.write(f"## {name}\n\n")

262

263

schema = self.schemas.get(name)

264

if schema and 'description' in schema:

265

f.write(f"{schema['description']}\n\n")

266

267

# Pretty print the schema

268

schema_str = self.schemas.prettyPrintByName(name)

269

f.write("```\n")

270

f.write(schema_str)

271

f.write("\n```\n\n")

272

273

# Add properties details

274

if schema and 'properties' in schema:

275

f.write("### Properties\n\n")

276

for prop_name, prop_def in schema['properties'].items():

277

f.write(f"- **{prop_name}** ({prop_def.get('type', 'unknown')}): ")

278

f.write(f"{prop_def.get('description', 'No description')}\n")

279

f.write("\n")

280

281

def get_schema_summary(self):

282

"""Get a summary of all schemas."""

283

schema_names = self.discovery_doc.get('schemas', {}).keys()

284

summary = {

285

'total_schemas': len(schema_names),

286

'schemas': {}

287

}

288

289

for name in schema_names:

290

schema = self.schemas.get(name)

291

if schema:

292

summary['schemas'][name] = {

293

'description': schema.get('description', ''),

294

'property_count': len(schema.get('properties', {})),

295

'type': schema.get('type', 'object')

296

}

297

298

return summary

299

300

# Usage

301

service = discovery.build('gmail', 'v1', credentials=credentials)

302

doc_generator = SchemaDocumentationGenerator(service._rootDesc)

303

304

# Generate documentation

305

doc_generator.generate_markdown_docs('gmail_schemas.md')

306

307

# Get summary

308

summary = doc_generator.get_schema_summary()

309

print(f"Found {summary['total_schemas']} schemas")

310

311

for name, info in summary['schemas'].items():

312

print(f"{name}: {info['property_count']} properties - {info['description'][:50]}...")

313

```

314

315

### Schema Comparison

316

317

```python

318

from googleapiclient.schema import Schemas

319

320

def compare_api_versions(service_name, version1, version2):

321

"""Compare schemas between two API versions."""

322

323

# Build services for both versions

324

service1 = discovery.build(service_name, version1, credentials=credentials)

325

service2 = discovery.build(service_name, version2, credentials=credentials)

326

327

schemas1 = Schemas(service1._rootDesc)

328

schemas2 = Schemas(service2._rootDesc)

329

330

# Get schema names from both versions

331

names1 = set(service1._rootDesc.get('schemas', {}).keys())

332

names2 = set(service2._rootDesc.get('schemas', {}).keys())

333

334

# Find differences

335

added_schemas = names2 - names1

336

removed_schemas = names1 - names2

337

common_schemas = names1 & names2

338

339

print(f"Schema comparison: {service_name} {version1} vs {version2}")

340

print(f"Added schemas: {len(added_schemas)}")

341

for name in sorted(added_schemas):

342

print(f" + {name}")

343

344

print(f"Removed schemas: {len(removed_schemas)}")

345

for name in sorted(removed_schemas):

346

print(f" - {name}")

347

348

print(f"Modified schemas:")

349

for name in sorted(common_schemas):

350

schema1 = schemas1.get(name)

351

schema2 = schemas2.get(name)

352

353

if schema1 != schema2:

354

print(f" ~ {name}")

355

356

# Compare properties

357

props1 = set(schema1.get('properties', {}).keys()) if schema1 else set()

358

props2 = set(schema2.get('properties', {}).keys()) if schema2 else set()

359

360

added_props = props2 - props1

361

removed_props = props1 - props2

362

363

if added_props:

364

print(f" Added properties: {', '.join(sorted(added_props))}")

365

if removed_props:

366

print(f" Removed properties: {', '.join(sorted(removed_props))}")

367

368

# Compare Gmail API versions

369

compare_api_versions('gmail', 'v1', 'v1') # Same version for demo

370

```

371

372

### Interactive Schema Explorer

373

374

```python

375

from googleapiclient.schema import Schemas

376

377

class InteractiveSchemaExplorer:

378

"""Interactive tool for exploring API schemas."""

379

380

def __init__(self, service_name, version):

381

self.service = discovery.build(service_name, version, credentials=credentials)

382

self.schemas = Schemas(self.service._rootDesc)

383

self.schema_names = list(self.service._rootDesc.get('schemas', {}).keys())

384

385

def explore(self):

386

"""Start interactive exploration."""

387

print(f"Schema Explorer - {len(self.schema_names)} schemas available")

388

print("Commands: list, show <name>, search <term>, quit")

389

390

while True:

391

try:

392

command = input("\nschema> ").strip().lower()

393

394

if command == 'quit':

395

break

396

elif command == 'list':

397

self._list_schemas()

398

elif command.startswith('show '):

399

schema_name = command[5:].strip()

400

self._show_schema(schema_name)

401

elif command.startswith('search '):

402

term = command[7:].strip()

403

self._search_schemas(term)

404

else:

405

print("Unknown command. Use: list, show <name>, search <term>, quit")

406

407

except KeyboardInterrupt:

408

break

409

except Exception as e:

410

print(f"Error: {e}")

411

412

def _list_schemas(self):

413

"""List all available schemas."""

414

print("Available schemas:")

415

for i, name in enumerate(sorted(self.schema_names)):

416

schema = self.schemas.get(name)

417

desc = schema.get('description', 'No description') if schema else 'No description'

418

print(f" {i+1:2d}. {name} - {desc[:60]}...")

419

420

def _show_schema(self, name):

421

"""Show detailed information about a schema."""

422

if name not in self.schema_names:

423

print(f"Schema '{name}' not found")

424

return

425

426

schema = self.schemas.get(name)

427

if not schema:

428

print(f"Could not retrieve schema '{name}'")

429

return

430

431

print(f"\nSchema: {name}")

432

if 'description' in schema:

433

print(f"Description: {schema['description']}")

434

435

print("\nSchema definition:")

436

print(self.schemas.prettyPrintByName(name))

437

438

def _search_schemas(self, term):

439

"""Search for schemas containing the term."""

440

matches = []

441

for name in self.schema_names:

442

schema = self.schemas.get(name)

443

if schema:

444

# Search in name and description

445

if (term.lower() in name.lower() or

446

term.lower() in schema.get('description', '').lower()):

447

matches.append(name)

448

449

if matches:

450

print(f"Found {len(matches)} matches:")

451

for name in sorted(matches):

452

schema = self.schemas.get(name)

453

desc = schema.get('description', 'No description') if schema else 'No description'

454

print(f" {name} - {desc[:60]}...")

455

else:

456

print(f"No schemas found containing '{term}'")

457

458

# Usage

459

explorer = InteractiveSchemaExplorer('gmail', 'v1')

460

# explorer.explore() # Uncomment for interactive use

461

```