or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-types.mdexperimental.mdextensions.mdfederation.mdfields-resolvers.mdframework-integrations.mdindex.mdrelay.mdschema-execution.mdutilities.md

federation.mddocs/

0

# Apollo Federation

1

2

Apollo Federation support for building distributed GraphQL architectures with multiple services and schema composition. Federation allows you to split your GraphQL schema across multiple services while presenting a unified API to clients.

3

4

## Capabilities

5

6

### Federation Schema

7

8

Federation-enabled schema class with support for Apollo Federation directives.

9

10

```python { .api }

11

class Schema:

12

"""Apollo Federation schema implementation."""

13

14

def __init__(

15

self,

16

query: Type = None,

17

mutation: Type = None,

18

subscription: Type = None,

19

*,

20

types: List[Type] = None,

21

extensions: List[SchemaExtension] = None,

22

enable_federation_2: bool = False

23

):

24

"""

25

Initialize Apollo Federation schema.

26

27

Args:

28

query: Root query type

29

mutation: Root mutation type (optional)

30

subscription: Root subscription type (optional)

31

types: Additional types to include in schema

32

extensions: Schema extensions

33

enable_federation_2: Enable Apollo Federation 2 features

34

"""

35

```

36

37

**Usage Example:**

38

39

```python

40

import strawberry

41

from strawberry.federation import Schema

42

43

@strawberry.federation.type(keys=["id"])

44

class User:

45

id: strawberry.ID

46

name: str

47

email: str

48

49

@strawberry.type

50

class Query:

51

@strawberry.field

52

def users(self) -> List[User]:

53

return get_all_users()

54

55

# Create federation schema

56

schema = Schema(

57

query=Query,

58

enable_federation_2=True

59

)

60

```

61

62

### Federation Type Decorator

63

64

Creates federated GraphQL object types with entity keys and federation directives.

65

66

```python { .api }

67

def type(

68

cls=None,

69

*,

70

name: str = None,

71

description: str = None,

72

keys: List[str] = None,

73

extend: bool = False,

74

resolvable: bool = True

75

) -> Any:

76

"""

77

Decorator to create federated GraphQL object types.

78

79

Args:

80

cls: The class to convert to a federated type

81

name: Custom name for the GraphQL type

82

description: Description for the GraphQL type

83

keys: List of key fields for entity resolution

84

extend: Whether this extends an existing entity from another service

85

resolvable: Whether this entity can be resolved by this service

86

87

Returns:

88

Federated GraphQL object type

89

"""

90

```

91

92

**Usage Examples:**

93

94

```python

95

# Basic federated entity

96

@strawberry.federation.type(keys=["id"])

97

class User:

98

id: strawberry.ID

99

name: str

100

email: str

101

102

# Multi-key entity

103

@strawberry.federation.type(keys=["id", "email"])

104

class User:

105

id: strawberry.ID

106

name: str

107

email: str

108

109

# Extending entity from another service

110

@strawberry.federation.type(keys=["id"], extend=True)

111

class User:

112

id: strawberry.ID = strawberry.federation.field(external=True)

113

posts: List["Post"]

114

115

@classmethod

116

def resolve_reference(cls, id: strawberry.ID):

117

# This service doesn't store user data, just references

118

return cls(id=id)

119

120

# Non-resolvable entity (just provides additional fields)

121

@strawberry.federation.type(keys=["id"], resolvable=False)

122

class User:

123

id: strawberry.ID = strawberry.federation.field(external=True)

124

computed_field: str

125

```

126

127

### Federation Field Decorator

128

129

Defines federated GraphQL fields with federation-specific directives.

130

131

```python { .api }

132

def field(

133

resolver: Callable = None,

134

*,

135

name: str = None,

136

description: str = None,

137

external: bool = False,

138

requires: str = None,

139

provides: str = None,

140

override_: str = None,

141

used_overridden: bool = False

142

) -> Any:

143

"""

144

Decorator to define federated GraphQL fields.

145

146

Args:

147

resolver: Custom resolver function for the field

148

name: Custom field name

149

description: Field description

150

external: Whether field is defined in another service

151

requires: Fields required from other services to resolve this field

152

provides: Fields this field provides to the entity

153

override_: Service that this field overrides (Federation 2)

154

used_overridden: Whether this field uses overridden field (Federation 2)

155

156

Returns:

157

Configured federated GraphQL field

158

"""

159

```

160

161

**Usage Examples:**

162

163

```python

164

@strawberry.federation.type(keys=["id"])

165

class User:

166

id: strawberry.ID

167

name: str = strawberry.federation.field(external=True)

168

email: str = strawberry.federation.field(external=True)

169

170

@strawberry.federation.field(requires="name email")

171

def display_name(self) -> str:

172

return f"{self.name} <{self.email}>"

173

174

@strawberry.federation.field(provides="title")

175

def latest_post(self) -> "Post":

176

post = get_latest_post(self.id)

177

return Post(id=post.id, title=post.title)

178

179

@strawberry.federation.type(keys=["id"])

180

class Post:

181

id: strawberry.ID

182

title: str = strawberry.federation.field(external=True)

183

content: str

184

185

# Override field from another service (Federation 2)

186

@strawberry.federation.field(override_="posts-service")

187

def view_count(self) -> int:

188

return get_accurate_view_count(self.id)

189

```

190

191

### Federation Interface

192

193

Creates federated GraphQL interfaces.

194

195

```python { .api }

196

def interface(

197

cls=None,

198

*,

199

name: str = None,

200

description: str = None,

201

keys: List[str] = None

202

) -> Any:

203

"""

204

Decorator to create federated GraphQL interfaces.

205

206

Args:

207

cls: The class to convert to a federated interface

208

name: Custom name for the GraphQL interface

209

description: Description for the GraphQL interface

210

keys: Key fields for interface entities

211

212

Returns:

213

Federated GraphQL interface type

214

"""

215

```

216

217

**Usage Example:**

218

219

```python

220

@strawberry.federation.interface(keys=["id"])

221

class Node:

222

id: strawberry.ID

223

224

@strawberry.federation.type(keys=["id"])

225

class User(Node):

226

id: strawberry.ID

227

name: str

228

229

@strawberry.federation.type(keys=["id"])

230

class Post(Node):

231

id: strawberry.ID

232

title: str

233

```

234

235

### Other Federation Decorators

236

237

All core decorators are available with federation support:

238

239

```python { .api }

240

def input(

241

cls=None,

242

*,

243

name: str = None,

244

description: str = None

245

) -> Any:

246

"""Federated GraphQL input type decorator."""

247

248

def enum(

249

cls=None,

250

*,

251

name: str = None,

252

description: str = None

253

) -> Any:

254

"""Federated GraphQL enum type decorator."""

255

256

def scalar(

257

cls=None,

258

*,

259

name: str = None,

260

description: str = None,

261

serialize: Callable = None,

262

parse_value: Callable = None

263

) -> Any:

264

"""Federated GraphQL scalar type decorator."""

265

266

def union(name: str, types: Tuple[Type, ...]) -> Any:

267

"""Federated GraphQL union type creator."""

268

```

269

270

## Entity Resolution

271

272

### Entity Reference Resolution

273

274

Federated entities must implement reference resolution for the Apollo Gateway.

275

276

```python { .api }

277

# Entities automatically get a resolve_reference class method

278

@strawberry.federation.type(keys=["id"])

279

class User:

280

id: strawberry.ID

281

name: str

282

email: str

283

284

@classmethod

285

def resolve_reference(cls, id: strawberry.ID):

286

"""

287

Resolve entity reference from Apollo Gateway.

288

289

Args:

290

id: Entity key value

291

292

Returns:

293

Entity instance

294

"""

295

user_data = get_user_by_id(id)

296

return cls(

297

id=user_data["id"],

298

name=user_data["name"],

299

email=user_data["email"]

300

)

301

```

302

303

### Complex Key Resolution

304

305

For entities with compound keys:

306

307

```python

308

@strawberry.federation.type(keys=["userId", "productId"])

309

class UserProductPreference:

310

user_id: strawberry.ID

311

product_id: strawberry.ID

312

rating: int

313

314

@classmethod

315

def resolve_reference(cls, user_id: strawberry.ID, product_id: strawberry.ID):

316

preference = get_user_product_preference(user_id, product_id)

317

return cls(

318

user_id=preference["user_id"],

319

product_id=preference["product_id"],

320

rating=preference["rating"]

321

)

322

```

323

324

### Multiple Key Variants

325

326

For entities that can be resolved by different key combinations:

327

328

```python

329

@strawberry.federation.type(keys=["id", "email"])

330

class User:

331

id: strawberry.ID

332

email: str

333

name: str

334

335

@classmethod

336

def resolve_reference(cls, **kwargs):

337

if "id" in kwargs:

338

user_data = get_user_by_id(kwargs["id"])

339

elif "email" in kwargs:

340

user_data = get_user_by_email(kwargs["email"])

341

else:

342

raise ValueError("No valid key provided")

343

344

return cls(

345

id=user_data["id"],

346

email=user_data["email"],

347

name=user_data["name"]

348

)

349

```

350

351

## Federation Patterns

352

353

### Service Composition Example

354

355

**Users Service:**

356

```python

357

# users_service.py

358

@strawberry.federation.type(keys=["id"])

359

class User:

360

id: strawberry.ID

361

name: str

362

email: str

363

created_at: datetime

364

365

@classmethod

366

def resolve_reference(cls, id: strawberry.ID):

367

user = get_user_from_database(id)

368

return cls(

369

id=user.id,

370

name=user.name,

371

email=user.email,

372

created_at=user.created_at

373

)

374

375

@strawberry.type

376

class Query:

377

@strawberry.field

378

def user(self, id: strawberry.ID) -> Optional[User]:

379

return User.resolve_reference(id)

380

381

@strawberry.field

382

def users(self) -> List[User]:

383

return [User.resolve_reference(u.id) for u in get_all_users()]

384

385

schema = strawberry.federation.Schema(query=Query)

386

```

387

388

**Posts Service:**

389

```python

390

# posts_service.py

391

@strawberry.federation.type(keys=["id"], extend=True)

392

class User:

393

id: strawberry.ID = strawberry.federation.field(external=True)

394

395

@strawberry.federation.field

396

def posts(self) -> List["Post"]:

397

return get_posts_by_user_id(self.id)

398

399

@strawberry.federation.type(keys=["id"])

400

class Post:

401

id: strawberry.ID

402

title: str

403

content: str

404

user_id: strawberry.ID

405

published_at: datetime

406

407

@strawberry.federation.field

408

def author(self) -> User:

409

return User(id=self.user_id)

410

411

@classmethod

412

def resolve_reference(cls, id: strawberry.ID):

413

post = get_post_from_database(id)

414

return cls(

415

id=post.id,

416

title=post.title,

417

content=post.content,

418

user_id=post.user_id,

419

published_at=post.published_at

420

)

421

422

@strawberry.type

423

class Query:

424

@strawberry.field

425

def post(self, id: strawberry.ID) -> Optional[Post]:

426

return Post.resolve_reference(id)

427

428

schema = strawberry.federation.Schema(query=Query, types=[User])

429

```

430

431

### Advanced Federation Features

432

433

#### Federation 2 Features

434

435

```python

436

# Enable Federation 2 features

437

schema = strawberry.federation.Schema(

438

query=Query,

439

enable_federation_2=True

440

)

441

442

@strawberry.federation.type(keys=["id"])

443

class User:

444

id: strawberry.ID

445

name: str

446

447

# Override field from another service

448

@strawberry.federation.field(override_="legacy-service")

449

def email(self) -> str:

450

return get_updated_email(self.id)

451

452

# Shareable fields (can be defined in multiple services)

453

@strawberry.federation.type(keys=["id"])

454

class Product:

455

id: strawberry.ID

456

457

@strawberry.federation.field(shareable=True)

458

def name(self) -> str:

459

return self._name

460

```

461

462

#### Computed Fields with Requirements

463

464

```python

465

@strawberry.federation.type(keys=["id"], extend=True)

466

class User:

467

id: strawberry.ID = strawberry.federation.field(external=True)

468

first_name: str = strawberry.federation.field(external=True)

469

last_name: str = strawberry.federation.field(external=True)

470

471

@strawberry.federation.field(requires="firstName lastName")

472

def full_name(self) -> str:

473

return f"{self.first_name} {self.last_name}"

474

```

475

476

#### Providing Fields to Other Services

477

478

```python

479

@strawberry.federation.type(keys=["id"])

480

class User:

481

id: strawberry.ID

482

email: str

483

484

@strawberry.federation.field(provides="username")

485

def profile(self) -> "UserProfile":

486

profile = get_user_profile(self.id)

487

return UserProfile(

488

user_id=self.id,

489

username=derive_username_from_email(self.email),

490

bio=profile.bio

491

)

492

493

@strawberry.federation.type(keys=["userId"])

494

class UserProfile:

495

user_id: strawberry.ID

496

username: str = strawberry.federation.field(external=True)

497

bio: str

498

```

499

500

## Federation Schema SDL

501

502

Generate federation-compatible SDL:

503

504

```python

505

from strawberry.printer import print_schema

506

507

# Print federation schema

508

federation_sdl = print_schema(schema)

509

print(federation_sdl)

510

```

511

512

**Example Output:**

513

```graphql

514

extend schema

515

@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@external", "@requires", "@provides"])

516

517

type User @key(fields: "id") {

518

id: ID!

519

name: String!

520

email: String!

521

posts: [Post!]!

522

}

523

524

type Post @key(fields: "id") {

525

id: ID!

526

title: String!

527

content: String!

528

author: User!

529

}

530

531

type Query {

532

user(id: ID!): User

533

post(id: ID!): Post

534

}

535

```

536

537

## Federation Gateway Integration

538

539

Services register with Apollo Gateway:

540

541

```javascript

542

// gateway.js

543

const { ApolloGateway } = require('@apollo/gateway');

544

const { ApolloServer } = require('apollo-server');

545

546

const gateway = new ApolloGateway({

547

serviceList: [

548

{ name: 'users', url: 'http://localhost:4001/graphql' },

549

{ name: 'posts', url: 'http://localhost:4002/graphql' },

550

{ name: 'reviews', url: 'http://localhost:4003/graphql' }

551

]

552

});

553

554

const server = new ApolloServer({

555

gateway,

556

subscriptions: false

557

});

558

```

559

560

This enables clients to make unified queries across all services:

561

562

```graphql

563

query UnifiedQuery {

564

user(id: "1") {

565

name

566

email

567

posts {

568

title

569

content

570

reviews {

571

rating

572

comment

573

}

574

}

575

}

576

}

577

```