or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdexecution-engine.mdexecution.mdindex.mdlanguage.mdtype-system.mdutilities.mdvalidation.md

utilities.mddocs/

0

# Schema Utilities and Introspection

1

2

Build schemas from SDL, perform introspection, compare schemas, and manipulate GraphQL type information for tooling and development. Provides comprehensive utilities for schema analysis, transformation, and development workflows.

3

4

## Capabilities

5

6

### Schema Construction

7

8

Build GraphQL schemas from various sources including Schema Definition Language (SDL) and introspection results.

9

10

```python { .api }

11

def build_schema(

12

source: Union[str, Source],

13

assume_valid: bool = False,

14

assume_valid_sdl: bool = False,

15

no_location: bool = False,

16

allow_legacy_fragment_variables: bool = False,

17

) -> GraphQLSchema

18

def build_ast_schema(document_ast: DocumentNode, assume_valid: bool = False, assume_valid_sdl: bool = False) -> GraphQLSchema

19

def build_client_schema(introspection: Dict[str, Any], assume_valid: bool = False) -> GraphQLSchema

20

def extend_schema(schema: GraphQLSchema, document_ast: DocumentNode, assume_valid: bool = False, assume_valid_sdl: bool = False) -> GraphQLSchema

21

```

22

23

**Parameters:**

24

- `source`: SDL string or Source object

25

- `document_ast`: Parsed SDL document

26

- `introspection`: Introspection query result

27

- `assume_valid`: Skip validation for performance

28

- `assume_valid_sdl`: Skip SDL validation

29

- `no_location`: Don't include location information in AST

30

- `allow_legacy_fragment_variables`: Allow legacy fragment variable syntax

31

32

**Returns:** GraphQLSchema instance

33

34

#### Usage Examples

35

36

```python

37

from graphql import build_schema, build_ast_schema, parse, build_client_schema

38

39

# Build from SDL string

40

schema = build_schema('''

41

type Query {

42

user(id: ID!): User

43

users: [User]

44

}

45

46

type User {

47

id: ID!

48

name: String!

49

email: String

50

posts: [Post]

51

}

52

53

type Post {

54

id: ID!

55

title: String!

56

content: String

57

author: User

58

}

59

''')

60

61

# Build from parsed AST

62

sdl_document = parse('''

63

type Query {

64

hello: String

65

}

66

''')

67

schema_from_ast = build_ast_schema(sdl_document)

68

69

# Build from introspection result

70

introspection_result = {

71

'data': {

72

'__schema': {

73

'queryType': {'name': 'Query'},

74

'types': [

75

{

76

'name': 'Query',

77

'kind': 'OBJECT',

78

'fields': [

79

{

80

'name': 'hello',

81

'type': {'name': 'String', 'kind': 'SCALAR'},

82

'args': []

83

}

84

]

85

}

86

]

87

}

88

}

89

}

90

client_schema = build_client_schema(introspection_result['data'])

91

```

92

93

### Schema Extension

94

95

Extend existing schemas with additional type definitions and modifications.

96

97

```python { .api }

98

def extend_schema(

99

schema: GraphQLSchema,

100

document_ast: DocumentNode,

101

assume_valid: bool = False,

102

assume_valid_sdl: bool = False

103

) -> GraphQLSchema

104

```

105

106

#### Usage Example

107

108

```python

109

from graphql import build_schema, extend_schema, parse

110

111

base_schema = build_schema('''

112

type Query {

113

user(id: ID!): User

114

}

115

116

type User {

117

id: ID!

118

name: String!

119

}

120

''')

121

122

extension = parse('''

123

extend type User {

124

email: String

125

posts: [Post]

126

}

127

128

type Post {

129

id: ID!

130

title: String!

131

author: User

132

}

133

134

extend type Query {

135

posts: [Post]

136

}

137

''')

138

139

extended_schema = extend_schema(base_schema, extension)

140

```

141

142

### Schema Introspection

143

144

Generate and process GraphQL introspection queries for schema discovery and tooling.

145

146

```python { .api }

147

def get_introspection_query(

148

description: bool = True,

149

specified_by_url: bool = False,

150

directive_is_repeatable: bool = False,

151

schema_description: bool = False,

152

input_value_deprecation: bool = False,

153

) -> str

154

155

def introspection_from_schema(

156

schema: GraphQLSchema,

157

options: Optional[IntrospectionOptions] = None

158

) -> Dict[str, Any]

159

160

class IntrospectionOptions:

161

description: bool = True

162

specified_by_url: bool = False

163

directive_is_repeatable: bool = False

164

schema_description: bool = False

165

input_value_deprecation: bool = False

166

167

IntrospectionQuery = Dict[str, Any]

168

```

169

170

#### Usage Example

171

172

```python

173

from graphql import get_introspection_query, introspection_from_schema, graphql_sync

174

175

# Get introspection query

176

introspection_query = get_introspection_query(

177

description=True,

178

specified_by_url=True

179

)

180

181

# Execute introspection against schema

182

result = graphql_sync(schema, introspection_query)

183

schema_info = result.data

184

185

# Or get introspection directly from schema

186

introspection_result = introspection_from_schema(schema)

187

print(introspection_result['__schema']['queryType']['name'])

188

```

189

190

### Schema Printing

191

192

Convert GraphQL schemas and types back to SDL representation.

193

194

```python { .api }

195

def print_schema(schema: GraphQLSchema, options: Optional[SchemaPrintOptions] = None) -> str

196

def print_type(type_: GraphQLNamedType, options: Optional[SchemaPrintOptions] = None) -> str

197

def print_introspection_schema(schema: GraphQLSchema) -> str

198

199

class SchemaPrintOptions:

200

comment_descriptions: bool = False

201

include_directives: Optional[Callable[[GraphQLDirective], bool]] = None

202

```

203

204

#### Usage Example

205

206

```python

207

from graphql import print_schema, print_type, print_introspection_schema

208

209

# Print entire schema as SDL

210

sdl = print_schema(schema)

211

print(sdl)

212

213

# Print specific type

214

user_type = schema.type_map['User']

215

user_sdl = print_type(user_type)

216

print(user_sdl)

217

218

# Print introspection schema

219

introspection_sdl = print_introspection_schema(schema)

220

print(introspection_sdl)

221

```

222

223

### Schema Sorting

224

225

Sort schema types and fields lexicographically for consistent output.

226

227

```python { .api }

228

def lexicographic_sort_schema(schema: GraphQLSchema) -> GraphQLSchema

229

```

230

231

#### Usage Example

232

233

```python

234

from graphql import lexicographic_sort_schema, print_schema

235

236

# Sort schema for consistent output

237

sorted_schema = lexicographic_sort_schema(schema)

238

sorted_sdl = print_schema(sorted_schema)

239

```

240

241

### Operation Processing

242

243

Extract and analyze operations from GraphQL documents.

244

245

```python { .api }

246

def get_operation_ast(document: DocumentNode, operation_name: Optional[str] = None) -> Optional[OperationDefinitionNode]

247

def get_operation_root_type(schema: GraphQLSchema, operation: OperationDefinitionNode) -> GraphQLObjectType

248

```

249

250

#### Usage Example

251

252

```python

253

from graphql import get_operation_ast, get_operation_root_type, parse

254

255

document = parse('''

256

query GetUser($id: ID!) {

257

user(id: $id) { name }

258

}

259

260

mutation CreateUser($input: UserInput!) {

261

createUser(input: $input) { id }

262

}

263

''')

264

265

# Get specific operation

266

query_op = get_operation_ast(document, 'GetUser')

267

mutation_op = get_operation_ast(document, 'CreateUser')

268

269

# Get root type for operation

270

query_root = get_operation_root_type(schema, query_op) # Returns Query type

271

mutation_root = get_operation_root_type(schema, mutation_op) # Returns Mutation type

272

```

273

274

### AST Processing and Manipulation

275

276

Convert between AST representations and Python objects, manipulate documents.

277

278

```python { .api }

279

def ast_to_dict(node: Node) -> Dict[str, Any]

280

def value_from_ast(value_node: Optional[ValueNode], type_: GraphQLInputType, variables: Optional[Dict[str, Any]] = None) -> Any

281

def value_from_ast_untyped(value_node: ValueNode, variables: Optional[Dict[str, Any]] = None) -> Any

282

def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]

283

def type_from_ast(schema: GraphQLSchema, type_node: TypeNode) -> Optional[GraphQLType]

284

def coerce_input_value(input_value: Any, type_: GraphQLInputType, on_error: Optional[Callable[[List[str], Any, GraphQLError], None]] = None) -> CoercionResult

285

```

286

287

#### Usage Example

288

289

```python

290

from graphql import ast_to_dict, value_from_ast, ast_from_value, parse_value, GraphQLString

291

292

# Convert AST to dictionary

293

value_ast = parse_value('"hello world"')

294

value_dict = ast_to_dict(value_ast)

295

print(value_dict) # {'kind': 'StringValue', 'value': 'hello world'}

296

297

# Extract value from AST with type

298

string_value = value_from_ast(value_ast, GraphQLString)

299

print(string_value) # 'hello world'

300

301

# Create AST from value

302

new_ast = ast_from_value('hello', GraphQLString)

303

print(new_ast.value) # 'hello'

304

```

305

306

### Document Manipulation

307

308

Manipulate and transform GraphQL documents.

309

310

```python { .api }

311

def concat_ast(*documents: DocumentNode) -> DocumentNode

312

def separate_operations(document: DocumentNode) -> Dict[str, DocumentNode]

313

def strip_ignored_characters(source: str) -> str

314

```

315

316

#### Usage Example

317

318

```python

319

from graphql import concat_ast, separate_operations, strip_ignored_characters, parse

320

321

# Concatenate documents

322

doc1 = parse('query A { user { name } }')

323

doc2 = parse('query B { posts { title } }')

324

combined = concat_ast(doc1, doc2)

325

326

# Separate operations

327

multi_op_doc = parse('''

328

query GetUser { user { name } }

329

query GetPosts { posts { title } }

330

''')

331

separated = separate_operations(multi_op_doc)

332

print(separated.keys()) # ['GetUser', 'GetPosts']

333

334

# Strip ignored characters (comments, extra whitespace)

335

minified = strip_ignored_characters('''

336

# This is a comment

337

query {

338

user {

339

name

340

}

341

}

342

''')

343

print(minified) # 'query{user{name}}'

344

```

345

346

### Type Information and Analysis

347

348

Get detailed type information for AST traversal and analysis.

349

350

```python { .api }

351

class TypeInfo:

352

def __init__(self, schema: GraphQLSchema, initial_type: Optional[GraphQLType] = None, get_field_def_fn: Optional[Callable] = None)

353

354

def get_type(self) -> Optional[GraphQLType]

355

def get_parent_type(self) -> Optional[GraphQLCompositeType]

356

def get_input_type(self) -> Optional[GraphQLInputType]

357

def get_parent_input_type(self) -> Optional[GraphQLInputType]

358

def get_field_def(self) -> Optional[GraphQLField]

359

def get_default_value(self) -> Optional[Any]

360

def get_directive(self) -> Optional[GraphQLDirective]

361

def get_argument(self) -> Optional[GraphQLArgument]

362

def get_enum_value(self) -> Optional[GraphQLEnumValue]

363

364

def enter(self, node: Node) -> None

365

def leave(self, node: Node) -> None

366

367

class TypeInfoVisitor:

368

def __init__(self, type_info: TypeInfo, visitor: Visitor)

369

```

370

371

#### Usage Example

372

373

```python

374

from graphql import TypeInfo, visit, Visitor

375

376

class FieldCollector(Visitor):

377

def __init__(self, type_info):

378

self.type_info = type_info

379

self.fields = []

380

381

def enter_field(self, node, key, parent, path, ancestors):

382

field_def = self.type_info.get_field_def()

383

parent_type = self.type_info.get_parent_type()

384

if field_def and parent_type:

385

self.fields.append(f"{parent_type.name}.{field_def.name}")

386

387

type_info = TypeInfo(schema)

388

collector = FieldCollector(type_info)

389

visitor = TypeInfoVisitor(type_info, collector)

390

391

document = parse('{ user { name email } posts { title } }')

392

visit(document, visitor)

393

print(collector.fields) # ['Query.user', 'User.name', 'User.email', 'Query.posts', 'Post.title']

394

```

395

396

### Type Comparisons

397

398

Compare and analyze relationships between GraphQL types.

399

400

```python { .api }

401

def is_equal_type(type_a: GraphQLType, type_b: GraphQLType) -> bool

402

def is_type_sub_type_of(schema: GraphQLSchema, maybe_sub_type: GraphQLType, super_type: GraphQLType) -> bool

403

def do_types_overlap(schema: GraphQLSchema, type_a: GraphQLCompositeType, type_b: GraphQLCompositeType) -> bool

404

```

405

406

#### Usage Example

407

408

```python

409

from graphql import is_equal_type, is_type_sub_type_of, do_types_overlap, GraphQLNonNull, GraphQLString

410

411

# Compare types

412

print(is_equal_type(GraphQLString, GraphQLString)) # True

413

print(is_equal_type(GraphQLString, GraphQLNonNull(GraphQLString))) # False

414

415

# Check subtype relationships

416

print(is_type_sub_type_of(schema, GraphQLNonNull(GraphQLString), GraphQLString)) # True

417

print(is_type_sub_type_of(schema, GraphQLString, GraphQLNonNull(GraphQLString))) # False

418

419

# Check type overlap (for unions/interfaces)

420

user_type = schema.type_map['User']

421

admin_type = schema.type_map.get('Admin')

422

if admin_type:

423

print(do_types_overlap(schema, user_type, admin_type))

424

```

425

426

### Schema Comparison

427

428

Find breaking and dangerous changes between schema versions.

429

430

```python { .api }

431

def find_breaking_changes(old_schema: GraphQLSchema, new_schema: GraphQLSchema) -> List[BreakingChange]

432

def find_dangerous_changes(old_schema: GraphQLSchema, new_schema: GraphQLSchema) -> List[DangerousChange]

433

434

class BreakingChange:

435

type: BreakingChangeType

436

description: str

437

438

class DangerousChange:

439

type: DangerousChangeType

440

description: str

441

442

class BreakingChangeType(Enum):

443

TYPE_REMOVED = "TYPE_REMOVED"

444

TYPE_CHANGED_KIND = "TYPE_CHANGED_KIND"

445

TYPE_REMOVED_FROM_UNION = "TYPE_REMOVED_FROM_UNION"

446

VALUE_REMOVED_FROM_ENUM = "VALUE_REMOVED_FROM_ENUM"

447

REQUIRED_INPUT_FIELD_ADDED = "REQUIRED_INPUT_FIELD_ADDED"

448

IMPLEMENTED_INTERFACE_REMOVED = "IMPLEMENTED_INTERFACE_REMOVED"

449

FIELD_REMOVED = "FIELD_REMOVED"

450

FIELD_CHANGED_KIND = "FIELD_CHANGED_KIND"

451

REQUIRED_ARG_ADDED = "REQUIRED_ARG_ADDED"

452

ARG_REMOVED = "ARG_REMOVED"

453

ARG_CHANGED_KIND = "ARG_CHANGED_KIND"

454

DIRECTIVE_REMOVED = "DIRECTIVE_REMOVED"

455

DIRECTIVE_ARG_REMOVED = "DIRECTIVE_ARG_REMOVED"

456

REQUIRED_DIRECTIVE_ARG_ADDED = "REQUIRED_DIRECTIVE_ARG_ADDED"

457

DIRECTIVE_REPEATABLE_REMOVED = "DIRECTIVE_REPEATABLE_REMOVED"

458

DIRECTIVE_LOCATION_REMOVED = "DIRECTIVE_LOCATION_REMOVED"

459

460

class DangerousChangeType(Enum):

461

VALUE_ADDED_TO_ENUM = "VALUE_ADDED_TO_ENUM"

462

TYPE_ADDED_TO_UNION = "TYPE_ADDED_TO_UNION"

463

OPTIONAL_INPUT_FIELD_ADDED = "OPTIONAL_INPUT_FIELD_ADDED"

464

OPTIONAL_ARG_ADDED = "OPTIONAL_ARG_ADDED"

465

IMPLEMENTED_INTERFACE_ADDED = "IMPLEMENTED_INTERFACE_ADDED"

466

ARG_DEFAULT_VALUE_CHANGE = "ARG_DEFAULT_VALUE_CHANGE"

467

```

468

469

#### Usage Example

470

471

```python

472

from graphql import find_breaking_changes, find_dangerous_changes, build_schema

473

474

old_schema = build_schema('''

475

type Query {

476

user(id: ID!): User

477

}

478

479

type User {

480

id: ID!

481

name: String!

482

}

483

''')

484

485

new_schema = build_schema('''

486

type Query {

487

user(id: ID!): User

488

users: [User]

489

}

490

491

type User {

492

id: ID!

493

name: String!

494

email: String

495

}

496

''')

497

498

breaking_changes = find_breaking_changes(old_schema, new_schema)

499

dangerous_changes = find_dangerous_changes(old_schema, new_schema)

500

501

print(f"Breaking changes: {len(breaking_changes)}")

502

print(f"Dangerous changes: {len(dangerous_changes)}")

503

504

for change in dangerous_changes:

505

print(f"{change.type.value}: {change.description}")

506

```

507

508

### Name Validation

509

510

Validate GraphQL names according to specification rules.

511

512

```python { .api }

513

def assert_valid_name(name: str) -> str

514

def is_valid_name_error(name: str) -> Optional[GraphQLError]

515

```

516

517

#### Usage Example

518

519

```python

520

from graphql import assert_valid_name, is_valid_name_error

521

522

# Valid names

523

assert_valid_name('User') # Returns 'User'

524

assert_valid_name('_internal') # Returns '_internal'

525

526

# Invalid names

527

try:

528

assert_valid_name('123Invalid') # Raises GraphQLError

529

except GraphQLError as e:

530

print(e.message)

531

532

error = is_valid_name_error('invalid-name')

533

if error:

534

print(error.message) # Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "invalid-name" does not.

535

```

536

537

## Types

538

539

```python { .api }

540

# Import required types

541

from typing import Any, Dict, List, Optional, Union, Callable, TypedDict

542

from graphql.type import GraphQLSchema, GraphQLType, GraphQLNamedType, GraphQLInputType, GraphQLCompositeType, GraphQLObjectType, GraphQLDirective, GraphQLField, GraphQLEnumValue

543

from graphql.language import DocumentNode, Source, Node, ValueNode, TypeNode, OperationDefinitionNode

544

from graphql.error import GraphQLError

545

546

# Schema construction types

547

SchemaPrintOptions = class SchemaPrintOptions

548

IntrospectionOptions = class IntrospectionOptions

549

IntrospectionQuery = Dict[str, Any]

550

551

# Type analysis types

552

TypeInfo = class TypeInfo

553

TypeInfoVisitor = class TypeInfoVisitor

554

555

# Schema comparison types

556

BreakingChange = class BreakingChange

557

DangerousChange = class DangerousChange

558

BreakingChangeType = Enum

559

DangerousChangeType = Enum

560

561

# Value coercion types

562

class CoercionResult:

563

value: Any

564

errors: List[GraphQLError]

565

```