Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1249,4 +1249,4 @@ This release is a major milestone for strawberry-django. Here are some of its hi
* Fix [#110](https://github.com/strawberry-graphql/strawberry-django/pull/110) - Add **kwargs passthrough on CUD mutations, enables "description" annotation from Strawberry. by [@JoeWHoward](https://github.com/JoeWHoward) in [#111](https://github.com/strawberry-graphql/strawberry-graphql-django/pull/111)
* Use auto from strawberry instead of define our own by [@bellini666](https://github.com/bellini666) in [#101](https://github.com/strawberry-graphql/strawberry-graphql-django/pull/101)
* Fix filtering cannot use relational reflection fields by [@star2000](https://github.com/star2000) in [#109](https://github.com/strawberry-graphql/strawberry-graphql-django/pull/109)
* refactor: Change the use of "is_unset" to "is UNSET" by [@bellini666](https://github.com/bellini666) in [#117](https://github.com/strawberry-graphql/strawberry-graphql-django/pull/117)
* refactor: Change the use of "is_unset" to "is UNSET" by [@bellini666](https://github.com/bellini666) in [#117](https://github.com/strawberry-graphql/strawberry-graphql-django/pull/117)
30 changes: 30 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
release type: minor
---

Add native federation support via `strawberry_django.federation` module.

New decorators that combine `strawberry_django` functionality with Apollo Federation:

- `strawberry_django.federation.type` - Federation-aware Django type with auto-generated `resolve_reference`
- `strawberry_django.federation.interface` - Federation-aware Django interface
- `strawberry_django.federation.field` - Federation-aware Django field with directives like `@external`, `@requires`, `@provides`

Example usage:

```python
import strawberry
import strawberry_django
from strawberry.federation import Schema

@strawberry_django.federation.type(models.Product, keys=["upc"])
class Product:
upc: strawberry.auto
name: strawberry.auto
price: strawberry.auto
# resolve_reference is automatically generated!

schema = Schema(query=Query)
```

The auto-generated `resolve_reference` methods support composite keys and multiple keys, and integrate with the query optimizer.
160 changes: 140 additions & 20 deletions docs/integrations/federation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,36 @@ title: Federation

Strawberry Django works seamlessly with
[Strawberry's Federation support](https://strawberry.rocks/docs/guides/federation).
Since federation is handled at the Strawberry level, you can use all federation
features directly with your Django types.
You can use either Strawberry's federation decorators directly or the Django-specific
`strawberry_django.federation` module which provides auto-generated `resolve_reference`
methods.

## Basic Usage
## Using `strawberry_django.federation` (Recommended)

Use Strawberry's federation decorators alongside `strawberry_django`:
The `strawberry_django.federation` module provides Django-aware federation decorators
that automatically generate `resolve_reference` methods for your entity types:

```python
import strawberry
import strawberry_django
from strawberry.federation.schema_directives import Key
from strawberry.federation import Schema as FederationSchema

from . import models


@strawberry_django.type(models.Product, directives=[Key(fields="upc")])
@strawberry_django.federation.type(models.Product, keys=["upc"])
class Product:
upc: strawberry.auto
name: strawberry.auto
price: strawberry.auto
# resolve_reference is automatically generated!


@strawberry_django.type(models.Review, directives=[Key(fields="id")])
@strawberry_django.federation.type(models.Review, keys=["id"])
class Review:
id: strawberry.auto
body: strawberry.auto
product: Product
```

## Creating a Federated Schema

Use `strawberry.federation.Schema` instead of the regular `strawberry.Schema`:

```python
import strawberry
from strawberry.federation import Schema


@strawberry.type
Expand All @@ -51,14 +45,120 @@ class Query:
return models.Product.objects.all()


schema = Schema(query=Query, enable_federation_2=True)
schema = FederationSchema(query=Query)
```

### Federation Parameters

The `@strawberry_django.federation.type` decorator accepts all standard
`@strawberry_django.type` parameters plus federation-specific ones:

| Parameter | Type | Description |
| ----------------- | ----------------- | ------------------------------------------------------------------------- |
| `keys` | `list[str]` | Key fields for entity resolution (e.g., `["id"]` or `["sku", "package"]`) |
| `extend` | `bool` | Whether this type extends a type from another subgraph |
| `shareable` | `bool` | Whether this type can be resolved by multiple subgraphs |
| `inaccessible` | `bool` | Whether this type is hidden from the public API |
| `authenticated` | `bool` | Whether this type requires authentication |
| `policy` | `list[list[str]]` | Access policy for this type |
| `requires_scopes` | `list[list[str]]` | Required OAuth scopes for this type |
| `tags` | `list[str]` | Metadata tags for this type |

### Multiple Keys

You can define multiple key fields:

```python
@strawberry_django.federation.type(models.Product, keys=["id", "upc"])
class Product:
id: strawberry.auto
upc: strawberry.auto
name: strawberry.auto
```

### Composite Keys

For composite keys (multiple fields that together form a key), use a space-separated
string:

```python
@strawberry_django.federation.type(models.ProductVariant, keys=["sku package"])
class ProductVariant:
sku: strawberry.auto
package: strawberry.auto
price: strawberry.auto
```

### Custom `resolve_reference`

If you need custom logic, you can still define your own `resolve_reference`:

```python
from strawberry.types.info import Info


@strawberry_django.federation.type(models.Product, keys=["upc"])
class Product:
upc: strawberry.auto
name: strawberry.auto

@classmethod
def resolve_reference(cls, upc: str, info: Info) -> "Product":
# Custom implementation with select_related
return models.Product.objects.select_related("category").get(upc=upc)
```

### Federation Fields

Use `strawberry_django.federation.field` for federation-specific field directives:

```python
@strawberry_django.federation.type(models.Product, keys=["id"])
class Product:
id: strawberry.auto
name: strawberry.auto = strawberry_django.federation.field(external=True)
price: strawberry.auto = strawberry_django.federation.field(shareable=True)
display_name: str = strawberry_django.federation.field(requires=["name"])
```

## Reference Resolvers
Field parameters:

| Parameter | Type | Description |
| ----------------- | ----------------- | ------------------------------------------------ |
| `authenticated` | `bool` | Whether this field requires authentication |
| `external` | `bool` | Field is defined in another subgraph |
| `requires` | `list[str]` | Fields required from other subgraphs |
| `provides` | `list[str]` | Fields this resolver provides to other subgraphs |
| `override` | `str` | Override field from another subgraph |
| `policy` | `list[list[str]]` | Access policy for this field |
| `requires_scopes` | `list[list[str]]` | Required OAuth scopes for this field |
| `shareable` | `bool` | Field can be resolved by multiple subgraphs |
| `tags` | `list[str]` | Metadata tags for this field |
| `inaccessible` | `bool` | Field is hidden from the public API |

### Interfaces

When other services need to resolve your Django entities, define `resolve_reference`:
Federation interfaces are also supported:

```python
@strawberry_django.federation.interface(models.Product, keys=["id"])
class ProductInterface:
id: strawberry.auto
name: strawberry.auto
```

## Using Strawberry's Federation Directly

You can also use Strawberry's federation decorators alongside `strawberry_django`:

```python
import strawberry
import strawberry_django
from strawberry.federation.schema_directives import Key

from . import models


@strawberry_django.type(models.Product, directives=[Key(fields="upc")])
class Product:
upc: strawberry.auto
Expand All @@ -70,6 +170,24 @@ class Product:
return models.Product.objects.get(upc=upc)
```

## Creating a Federated Schema

Use `strawberry.federation.Schema` instead of the regular `strawberry.Schema`:

```python
from strawberry.federation import Schema


@strawberry.type
class Query:
@strawberry_django.field
def products(self) -> list[Product]:
return models.Product.objects.all()


schema = Schema(query=Query)
```

## Django-Specific Considerations

### Query Optimizer
Expand All @@ -82,11 +200,13 @@ from strawberry_django.optimizer import DjangoOptimizerExtension

schema = Schema(
query=Query,
enable_federation_2=True,
extensions=[DjangoOptimizerExtension],
)
```

The auto-generated `resolve_reference` methods integrate with the query optimizer
when using `strawberry_django.federation`.

### Authentication

When using federation with Django authentication, ensure your gateway forwards
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ classifiers = [
"Framework :: Django :: 6.0",
]
requires-python = ">=3.10,<4.0"
dependencies = ["django>=4.2", "asgiref>=3.8", "strawberry-graphql>=0.288.0"]
dependencies = ["django>=4.2", "asgiref>=3.8", "strawberry-graphql>=0.303.0"]

[project.urls]
homepage = "https://strawberry.rocks/docs/django"
Expand Down Expand Up @@ -61,7 +61,7 @@ dev = [
"pytest-watch>=4.2.0",
"pytest-xdist>=3.8.0",
"ruff>=0.14.0",
"django-polymorphic>=4.1.0",
"django-polymorphic>=4.1.0,<4.6",
"setuptools>=80.1.0",
"psycopg>=3.2.10",
"psycopg-binary>=3.2.10",
Expand Down
3 changes: 2 additions & 1 deletion strawberry_django/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import warnings
from typing import TYPE_CHECKING, Any

from . import auth, filters, mutations, ordering, pagination, relay
from . import auth, federation, filters, mutations, ordering, pagination, relay
from .fields.field import connection, field, node, offset_paginated
from .fields.filter_order import filter_field, order_field
from .fields.filter_types import (
Expand Down Expand Up @@ -58,6 +58,7 @@
"auth",
"connection",
"django_resolver",
"federation",
"field",
"filter_field",
"filter_type",
Expand Down
27 changes: 27 additions & 0 deletions strawberry_django/federation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Federation support for strawberry-django.

This module provides Django-aware federation decorators that combine
`strawberry_django` functionality with Apollo Federation support.

- `type` - Federation-aware Django type decorator
- `interface` - Federation-aware Django interface decorator
- `field` - Federation-aware Django field decorator

The type and interface decorators automatically generate `resolve_reference`
methods for entity types (those with `@key` directives).

See docs/integrations/federation.md for full usage examples.
"""

from .field import field
from .resolve import generate_resolve_reference, resolve_model_reference
from .type import interface
from .type import type as type # noqa: A004

__all__ = [
"field",
"generate_resolve_reference",
"interface",
"resolve_model_reference",
"type",
]
Loading
Loading