# Technical Documentation: strawberry-graphql/strawberry

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/strawberry-graphql/strawberry)

### Overview (`README.md`)

<img src="https://github.com/strawberry-graphql/strawberry/raw/main/.github/logo.png" width="124" height="150">

# Strawberry GraphQL

> Python GraphQL library based on dataclasses

[](https://discord.gg/ZkRTEJQ)
[](https://pypi.org/project/strawberry-graphql/)

## Installation ( Quick Start )

The quick start method provides a server and CLI to get going quickly. Install
with:

```shell
pip install "strawberry-graphql[cli]"
```

## Getting Started

Create a file called `app.py` with the following code:

```python
import strawberry


@strawberry.type
class User:
    name: str
    age: int


@strawberry.type
class Query:
    @strawberry.field
    def user(self) -> User:
        return User(name="Patrick", age=100)


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

This will create a GraphQL schema defining a `User` type and a single query
field `user` that will return a hardcoded user.

To serve the schema using the dev server run the following command:

```shell
strawberry dev app
```

Open the dev server by clicking on the following link:
[http://0.0.0.0:8000/graphql](http://0.0.0.0:8000/graphql)

This will open GraphiQL where you can test the API.

### Type-checking

Strawberry comes with a [mypy] plugin that enables statically type-checking your
GraphQL schema. To enable it, add the following lines to your `mypy.ini`
configuration:

```ini
[mypy]
plugins = strawberry.ext.mypy_plugin
```

[mypy]: http://www.mypy-lang.org/

### Django Integration

A Django view is provided for adding a GraphQL endpoint to your application.

1. Add the app to your `INSTALLED_APPS`.

```python
INSTALLED_APPS = [
    ...,  # your other apps
    "strawberry.django",
]
```

2. Add the view to your `urls.py` file.

```python
from strawberry.django.views import GraphQLView
from .schema import schema

urlpatterns = [
    ...,
    path("graphql", GraphQLView.as_view(schema=schema)),
]
```

## Examples

* [Various examples on how to use Strawberry](https://github.com/strawberry-graphql/examples)
* [Full stack example using Starlette, SQLAlchemy, Typescript codegen and Next.js](https://github.com/jokull/python-ts-graphql-demo)
* [Quart + Strawberry tutorial](https://github.com/rockyburt/Ketchup)

## Contributing

We use [uv](https://docs.astral.sh/uv) to manage dependencies, to
get started follow these steps:

```shell
git clone https://github.com/strawberry-graphql/strawberry
cd strawberry
uv sync
uv run pytest
```

For all further detail, check out the [Contributing Page](CONTRIBUTING.md)


### Pre commit

We have a configuration for
[pre-commit](https://github.com/pre-commit/pre-commit), to add the hook run the
following command:

```shell
pre-commit install
```

## Links

- Project homepage: https://strawberry.rocks
- Repository: https://github.com/strawberry-graphql/strawberry
- Issue tracker: https://github.com/strawberry-graphql/strawberry/issues
  - In case of sensitive bugs like security vulnerabilities, please contact
    patrick.arminio@gmail.com directly instead of using the issue tracker. We
    value your effort to improve the security and privacy of this project!

## Licensing

The code in this project is licensed under MIT license. See [LICENSE](./LICENSE)
for more information.

---

### Overview (`docs/README.md`)

---
title: Strawberry docs
---

# Strawberry docs

- [Getting started](./index.md)

## General

- [Schema basics](./general/schema-basics.md)
- [Queries](./general/queries.md)
- [Mutations](./general/mutations.md)
- [Subscriptions](./general/subscriptions.md)
- [Multipart Subscriptions](./general/multipart-subscriptions.md)
- [Errors](./errors)
- [Upgrading Strawberry](./general/upgrades.md)
- [Breaking changes](./breaking-changes.md)
- [FAQ](./faq.md)

## Types

- [Schema](./types/schema.md)
- [Operation Directives](./types/operation-directives.md)
- [Schema Directives](./types/schema-directives.md)
- [Schema configurations](./types/schema-configurations.md)
- [Scalars](./types/scalars.md)
- [Object types](./types/object-types.md)
- [Interfaces](./types/interfaces.md)
- [Input types](./types/input-types.md)
- [Enums](./types/enums.md)
- [Generics](./types/generics.md)
- [Resolvers](./types/resolvers.md)
- [Union types](./types/union.md)
- [Lazy types](./types/lazy.md)
- [Exceptions](./types/exceptions.md)
- [Private/External Fields](./types/private.md)
- [Defer and Stream](./types/defer-and-stream.md)

## Codegen

- [Schema codegen](./codegen/schema-codegen.md)
- [Query codegen](./codegen/query-codegen.md)

## Guides

- [Accessing parent data](./guides/accessing-parent-data.md)
- [Authentication](./guides/authentication.md)
- [DataLoaders](./guides/dataloaders.md)
- [Dealing with errors](./guides/errors.md)
- [Federation](./guides/federation.md)
- [Federation V1](./guides/federation-v1.md)
- [Relay](./guides/relay.md)
- [File upload](./guides/file-upload.md)
- [Pagination](./guides/pagination/overview.md)
  - [Implementing Offset Pagination](./guides/pagination/offset-based.md)
  - [Implementing Cursor Pagination](./guides/pagination/cursor-based.md)
  - [Implementing the Connection specification](./guides/pagination/connections.md)
- [Permissions](./guides/permissions.md)
- [Built-in server](./guides/server.md)
- [Tools](./guides/tools.md)
- [Schema export](./guides/schema-export.md)
- [Convert to dictionary](./guides/convert-to-dictionary.md)
- [Query Batching](./guides/query-batching.md)

## Extensions

- [Introduction](./extensions)
- [Schema extensions](./guides/custom-extensions.md)
- [Field extensions](./guides/field-extensions.md)

## Editor integration

- [Mypy](./editors/mypy.md)
- [Visual Studio Code](./editors/vscode.md)

## Concepts

- [Async](./concepts/async.md)
- [Type hints](./concepts/typings.md)

## Integrations

- [AIOHTTP](./integrations/aiohttp.md)
- [ASGI](./integrations/asgi.md)
- [Django](./integrations/django.md)
- [Channels](./integrations/channels.md)
- [FastAPI](./integrations/fastapi.md)
- [Flask](./integrations/flask.md)
- [Quart](./integrations/quart.md)
- [Sanic](./integrations/sanic.md)
- [Chalice](./integrations/chalice.md)
- [Starlette](./integrations/starlette.md)
- [Litestar](./integrations/litestar.md)
- [Creating an integration](./integrations/creating-an-integration.md)
- [Pydantic **experimental**](./integrations/pydantic.md)

## Federation

- [Introduction](./federation/introduction.md)
- [Entities](./federation/entities.md)
- [Entity interfaces](./federation/entity-interfaces.md)
- [Custom directives](./federation/custom_directives.md)

## Operations

- [Deployment](./operations/deployment.md)
- [Testing](./operations/testing.md)
- [Tracing](./operations/tracing.md)

---

### Overview (`tests/benchmarks/README.md`)

# Strawberry benchmarks

This directory is the authoritative suite for current Strawberry. Benchmarks verify
GraphQL errors, output shapes and workload sizes as well as measuring execution.
CPU simulation, native wall-clock time and allocations are different measurements;
never splice their results into one time series.

## Run locally

Install the locked environment, then run the correctness checks without timing:

```sh
uv sync --locked
uv run pytest tests/benchmarks tests/test_benchmark_contracts.py -p no:codeflash-benchmark
```

`pytest-codspeed` owns the benchmark fixture. Disable the Codeflash benchmark
plugin explicitly so that plugin discovery cannot silently select another fixture.
Without `--codspeed`, each callback executes once and its assertions still run.

For native elapsed-time measurements, run serially on an otherwise idle machine:

```sh
uv run python -m tests.benchmarks.metadata benchmark-artifacts/environment.json --instrument walltime
uv run pytest tests/benchmarks --codspeed --codspeed-mode walltime \
  -p no:codeflash-benchmark -m 'not benchmark_stress' \
  --codspeed-warmup-time 0.1 --codspeed-max-time 1 --codspeed-max-rounds 30 \
  --junitxml=benchmark-artifacts/results.xml -o junit_family=legacy
```

Raw measurements are written to `.codspeed/results_*.json`. Archive these with
`benchmark-artifacts/`; HTTP response byte counts are in the JUnit properties.
Local timings are observations, not directly comparable with another machine.

CPU simulation and allocation measurements run through the CodSpeed action in CI.
A local instrumented simulation/memory run additionally requires the appropriate
CodSpeed runner; passing `--codspeed-mode simulation` alone does not install it.
See [CodSpeed's Python documentation](https://codspeed.io/docs/benchmarks/python).

## Workload groups

| Marker | Execution | Purpose |
| --- | --- | --- |
| Neither native nor stress | Every PR/main push, Python 3.14.7, four CodSpeed simulation shards | CPU regression detection |
| `benchmark_native` | Scheduled native runs | ASGI/FastAPI request parsing through response consumption, and fresh-process import/schema startup |
| `benchmark_stress` | Weekly or explicitly requested native runs | Largest argument lists, interface counts, stadium datasets and subscription streams |
| `benchmark_memory` | Scheduled Linux CodSpeed memory job | Schema construction, large result construction, cache churn and subscription cleanup |

Markers may overlap. A plain correctness run covers every group. The native
workflow in `strawberry-graphql/benchmarks` uses the existing Mac runner with Python
3.14.7, the latest stable release as of September 7, 2026. All three instruments
pin this exact version; a Python upgrade starts a new baseline.
The main repository's `benchmark-memory.yml` runs bounded allocation workloads.
New native and memory results are advisory; the workflows do not invent regression
thresholds or change the repository's existing CodSpeed gate settings.

## Measurement boundaries

- Schemas, queries, expected responses and reusable fixtures are prepared outside
  the timed callback unless construction is explicitly the workload.
- Async execution uses `benchmark_loop`, with loop creation and shutdown outside
  timing. Driving the loop, coroutine creation and resolver work stay measured.
- The matched async resolver yields once with `sleep(0)`; it models scheduling,
  not database or network latency. DataLoader uses the same convention.
- Cache benchmarks reset shared module-level caches before **each round** with
  `benchmark.pedantic(..., iterations=1)`. Warm cases prime outside measurement;
  assertions verify the hit/miss contract. New schemas alone do not reset caches.
- Result assertions run after measurement. Subscription cases collect returned
  results, verify the exact count and payloads, and explicitly close generators.
  The setup case measures 100 setup/first-event/close cycles; the stream case
  includes consuming and retaining its requested event count.
- Federation entity inputs are recreated outside timing before every round,
  because entity resolution consumes the representation's `__typename` key.
- The stadium and application workloads intentionally construct resolver data.
  The matched execution workload reuses prepared objects to isolate execution.
- Schema construction starts from already-decorated types and builds ten schemas
  per measurement. CodSpeed's simulation starts each measurement with empty CPU
  caches, and unrelated changes moved the estimate of a single small build by up
  to 13%. The process-startup case intentionally includes interpreter launch,
  import, decoration, schema construction and a small verified query.
- HTTP uses an in-process HTTPX ASGI transport. It includes client/transport work,
  request parsing, execution, JSON encoding and response consumption, but no
  socket, network or external database. Fixed requests use compact JSON responses;
  both decoded content and exact response bytes are checked.
- CodSpeed disables cyclic GC during measurements. Allocator/RSS measurements
  and repeated subscription cleanup are diagnostic; a single sample is not proof
  of a leak. Collect sustained native runs when investigating retention.
- Permission and handled-error queries perform ten unmeasured warmup requests
  before timing one complete request. Parsing, validation, permission checks,
  exception handling and allocation costs are included in the measured callback.
  Native timing collects 30 rounds; simulation measures one request, as it does
  for other pedantic benchmarks.

## Comparing revisions

Metadata records the code revision, worktree-change flag, workload digest, lockfile
digest, Python build, platform, resolved packages, GC/cache policies and runner
identity. Keep those artifacts with results. Do not compare uncommitted working trees as
published baselines. Capture actual hardware identity and runner changes when
moving the native job; an architecture label alone does not identify a CPU.

To attribute a change to Strawberry, run the **same benchmark code and dependencies**
against both source revisions. A changed lockfile is a dependency experiment as
well as a code change. If an old version cannot execute the new workload, record
it as unsupported rather than turning its error into a timing. Run unchanged
revisions repeatedly to establish variability before adding per-case thresholds.
CPU estimates are not measured HTTP latency; round timings are not request p95/p99.
Missing, skipped or failed runs are not performance improvements.

## Suite version 2 and historical continuity

Functions renamed with `_v2` intentionally start new series:

- Argument conversion excludes configuration construction and the full-list assertion.
- Application, interface, complex/generic, extension, stadium and DataLoader
  execution exclude loop setup/shutdown. Application data uses a fixed date and
  deterministic pets; complex schema IDs now use their seed instead of `str(int)`.
- Extension benchmarks use classes/factories rather than deprecated shared instances.
- Subscription measurements close streams and collect results for complete validation.
- Parser-cache cases have explicit uncached/cold/warm contracts, and optionally
  include the validation cache.
- Schema construction builds ten schemas per measurement instead of one.

Existing synchronous execution and exception-handler timings keep their names
because their new assertions run outside the measured callback. The awaitable
benchmarks added separately in main retain their existing definitions and IDs.
Stress sizes retain their parameter IDs, even though their measurement schedule
changes. The stadium adds a smaller 1,800-seat PR case; the 45,000/90,000-seat cases
are available as stress cases.

The dashboard at [speed.strawberry.rocks](https://speed.strawberry.rocks/) uses ASV
to chart native walltime measurements from this pytest-codspeed suite. The
[reporting workflow](https://github.com/strawberry-graphql/benchmarks) tracks main
and future stable releases, retaining results from the modern suite after
resetting obsolete history. Changed workloads or environments start separate
series. Its methodology page links the CPU and memory measurements.

---

### Overview (`tests/types/cross_module_resolvers/README.md`)

# Module tests

This directory contains the modules needed for the
`test_cross_module_resolvers.py` file in the directory above.

## Problem

In an earlier strawberry version the resolver did add itself as the
origin of fields. This caused the type resolving to fail when using
a resolver from a different module:

```python
from other_module import generic_resolver


@strawberry.field
class Foo:
    bar: "Bar" = strawberry.field(resolver=generic_resolver)


@strawberry.field
class Bar:
    awesome: bool
```

Since the `origin` of the `Foo.bar` field was set to
`generic_resolver` the `Bar` type was not looked up relative to the
`Foo` class but the `generic_resolver` causing the type lookup to
fail.

## Robust tests

**Important**: For these tests not to mask any incorrect resolution
behavior, all type names are unique across all modules. E.g. when
importing `a.AObject` into the `c` module it is renamed to `C_AObject`.
This ensures that we can discern which module the object is coming from
and any incorrect resolution behavior can be detected.

## Submodules

This module contains four submodules which are used to test various
cross-module references:

- `a` contains standalone types
- `b` contains standalone types
- `c` contains types that either inherit from the types in the
    `a` and `b` module or contain references to them
- `x` contains typeless (generic) resolvers

---

### Index (`docs/index.md`)

---
title: Getting started with Strawberry
---

# Getting started with Strawberry

This tutorial will help you:

- Obtain a basic understanding of GraphQL principles
- Define a GraphQL schema using Strawberry
- Run the Strawberry dev server that lets you execute queries against your
  schema

This tutorial assumes that you are familiar with the command line and Python,
and that you have a recent version of Python (3.11+) installed.

Strawberry is built on top of Python’s
[dataclasses](https://realpython.com/python-data-classes/) and
[type hints](https://docs.python.org/3/library/typing.html) functionality.

## Step 1: Create a new project and install Strawberry

Let’s create a new folder:

```shell
mkdir strawberry-demo
cd strawberry-demo
```

After that we need a new virtualenv:

```shell
python -m venv virtualenv
```

Activate the virtualenv and then install strawberry plus the dev server.

```shell
source virtualenv/bin/activate
pip install 'strawberry-graphql[cli]'
```

## Step 2: Define the schema

Every GraphQL server uses a **schema** to define the structure of the data that
clients can query. In this example, we will create a server for querying a
collection of books by title and author.

In your favorite editor create a file called `schema.py`, with the following
contents:

```python
import typing
import strawberry


@strawberry.type
class Book:
    title: str
    author: str


@strawberry.type
class Query:
    books: typing.List[Book]
```

This will create a GraphQL schema where clients will be able to execute a query
named `books` that will return a list of zero or more books.

## Step 3: Define your data set

Now that we have our structure of your schema, we can define the data itself.
Strawberry can work with any data source (for example a database, a REST API,
files, etc). For this tutorial we will be using hard-coded data.

Let’s create a function that returns some books.

```python
def get_books():
    return [
        Book(
            title="The Great Gatsby",
            author="F. Scott Fitzgerald",
        ),
    ]
```

Since strawberry makes uses of python classes to create the schema, this means
that we can also reuse them to create the data objects.

## Step 4: Define a resolver

We now have a function that returns some books, but Strawberry doesn’t know it
should use it when executing a query. To fix this we need to update our query to
specify the [resolver](/docs/types/resolvers) for our books. A resolver tells
Strawberry how to fetch the data associated with a particular field.

Let’s update our Query:

```python
@strawberry.type
class Query:
    books: typing.List[Book] = strawberry.field(resolver=get_books)
```

Using `strawberry.field` allows us to specify a resolver for a particular field.

<Note>

We didn't have to specify any resolver for the Book's fields, this is because
Strawberry adds a default for each field, returning the value of that field.

</Note>

## Step 5: Create our schema and run it

We have defined our data and query, now what we need to do is create a GraphQL
schema and start the server.

To create the schema add the following code:

```python
schema = strawberry.Schema(query=Query)
```

Then run the following command

```shell
strawberry dev schema
```

This will start a dev server, you should see the following output:

```text
Running strawberry on http://0.0.0.0:8000/graphql 🍓
```

## Step 6: execute your first query

We can now execute GraphQL queries. Strawberry comes with a tool called
**GraphiQL**. To open it go to
[http://0.0.0.0:8000/graphql](http://0.0.0.0:8000/graphql)

You should see something like this:



The GraphiQL UI includes:

- A text area (to the left) for writing queries
- A Play button (the triangle button in the middle) for executing queries
- A text area (to the right) for viewing query results Views for schema
  inspection and generated documentation (via tabs on the right side)

Our server supports a single query named books. Let's execute it!

Paste the following string into the left area and then click the play button:

```graphql
{
  books {
    title
    author
  }
}
```

You should see the hardcoded data appear on the right side:



GraphQL allows clients to query only the fields they need, go ahead and remove
`author` from the query and run it again. The response should now only show the
title for each book.

## Next steps



Well done! You just created your first GraphQL API using Strawberry 🙌!

Check out the following resources to learn more about GraphQL and Strawberry.

- [Schema Basics](./general/schema-basics.md)
- [Resolvers](./types/resolvers.md)
- [Deployment](./operations/deployment.md)

---

### Integrations Index (`docs/integrations/index.md`)

---
title: Integrations
---

# Integration

Strawberry can be used with a variety of web frameworks and libraries. Here is a
list of the integrations along with the features they support.

Note, this table is not up to date, and this page shouldn't be linked anywhere
(yet).

| name                        | Supports sync | Supports async       | Supports subscriptions via websockets | Supports subscriptions via multipart HTTP | Supports file uploads | Supports batch queries |
| --------------------------- | ------------- | -------------------- | ------------------------------------- | ----------------------------------------- | --------------------- | ---------------------- |
| [django](./django.md)       | ✅            | ✅ (with Async view) | ❌ (use Channels for websockets)      | ✅                                        | ✅                    | ❌                     |
| [starlette](./starlette.md) | ✅            | ✅                   | ✅                                    | ✅                                        | ✅                    | ✅                     |
| [aiohttp](./aiohttp.md)     | ✅            | ✅                   | ✅                                    | ✅                                        | ✅                    | ✅                     |
| [flask](./flask.md)         | ✅            | ✅                   | ❌                                    | ❌                                        | ✅                    | ✅                     |
| [channels](./channels.md)   | ✅            | ✅                   | ✅                                    | ❌                                        | ✅                    | ✅                     |
| [fastapi](./fastapi.md)     | ✅            | ✅                   | ✅                                    | ✅                                        | ✅                    | ✅                     |

---

### Guides Pagination Overview (`docs/guides/pagination/overview.md`)

---
title: Pagination - Overview
---

# Pagination

Whenever we deal with lists in GraphQL, we usually need to limit the number of
items returned. Surely, we don't want to send massive lists of items that take a
considerable toll on the server! The goal of this guide is to help you get going
fast with pagination!

## Pagination at a Glance

Let us take a look at some of the common ways pagination can be implemented
today!

### Offset-Based Pagination

This type of pagination is widely used, and it is similar to the syntax we use
when looking up database records.

Here, the client specifies:

- `limit`: The number of items to be obtained at a time, and
- `offset`: The number of items to be skipped from the beginning.

Implementing offset-based pagination with an SQL database is straightforward. We
use the `limit` and `offset` values given to query for the items.

Offset-based pagination also provides us the ability to skip ahead to any
offset, without first needing to get all the items before it.

Let us understand offset-based pagination better, with an example. Let us assume
that we want to request a list of users, two at a time, from a server. We start
by sending a request to the server, with the desired `limit` and `offset`
values.

```json
{
  "limit": 2,
  "offset": 0
}
```

<Note>

We are not sending GraphQL requests here, don't worry about the request format
for now! We are looking into pagination conceptually. We'll implement pagination
in GraphQL later!

</Note>

The response from the server would be:

```json
{
  "users": [
    {
      "id": 1,
      "name": "Norman Osborn",
      "occupation": "Founder, Oscorp Industries",
      "age": 42
    },
    {
      "id": 2,
      "name": "Peter Parker",
      "occupation": "Freelance Photographer, The Daily Bugle",
      "age": 20
    }
  ]
}
```

To get the next two users, we can send another request, incrementing `offset` by
the value of `limit`.

```json
{
  "limit": 2,
  "offset": 2
}
```

We can repeat this process, incrementing `offset` by the value of `limit`, until
we get an empty result.

#### Pagination Metadata

In the example above, the result contained no metadata, only the items at the
requested offset and limit.

It may be useful to add metadata to the result. For example, the metadata may
specify how many items there are in total, so that the client knows what the
greatest offset value can be.

```json
{
  "users": [
    ...
  ]
  "metadata": {
    "count": 25
  }
}
```

#### Using page_number Instead of offset

Instead of using `limit` and `offset` as the pagination parameters, it may be
more useful to use `page_number` and `page_size`.

In such a case, the metadata in the result can be `pages_count`. The client
starts the pagination at `page_number` 1, incrementing by 1 each time to get the
next page, and ending when `page_size` is reached.

This approach may be more in line with what a typical client actually needs when
paginating.

#### Limitations of Offset-Based Pagination

Offset-based pagination has a few limitations:

- It is not suitable for large datasets, because we need to access offset +
  limit number of items from the dataset, before discarding the offset and only
  returning the requested items.
- It doesn't work well in environments where records are frequently added or
  removed, because in such cases, the page window becomes inconsistent and
  unreliable. This may result in duplicate items or skipped items across pages.

However, it provides a quick way to get started, and works well with
small-medium datasets. When your dataset scales, you will need a reliable and
consistent way to handle pagination.

### Cursor based pagination

<Note>

Strawberry provides a cursor based pagination implementing the
[relay spec](https://relay.dev/docs/guides/graphql-server-specification/). You
can read more about it in the [relay](../relay) page.

</Note>

Cursor based pagination, also known as keyset pagination, works by returning a
pointer to a specific item in the dataset. On subsequent requests, the server
returns results after the given pointer. This method addresses the drawbacks of
using offset pagination, but does so by making certain trade offs:

- The cursor must be based on a unique, sequential identifier in the given
  source.
- There is no concept of the total number of pages or results in the dataset.
- The client can’t jump to a specific page.

Let us understand cursor based pagination better, with the example given below.
We want to request a list of users, 2 at a time, from the server. We don't know
the cursor initially, so we will assign it a null value.

```json
{
  "limit": 2,
  "cursor": null
}
```

The response from the server would be:

```json
{
  "users": [
    {
      "id": 3,
      "name": "Harold Osborn",
      "occupation": "President, Oscorp Industries",
      "age": 19
    },
    {
      "id": 4,
      "name": "Eddie Brock",
      "occupation": "Journalist, The Eddie Brock Report",
      "age": 20
    }
  ],
  "next_cursor": "3"
}
```

The next cursor returned by the server can be used to get the next set of users
from the server.

```json
{
  "limit": 2,
  "cursor": "3"
}
```

This is an example of forward pagination, but pagination can be done backwards
too!

## Implementing pagination in GraphQL

Let us look at how we can implement pagination in GraphQL.

- [Implementing Offset Pagination](./offset-based.md)
- [Implementing Cursor Pagination](./cursor-based.md)
- [Implementing the Relay Connection Specification](./connections.md)

---

###  Test (`docs/_test.md`)

---
title: Test doc page
toc: true
---

# This is a test doc page

Some examples of things you can do in docs.

## Code highlighting

Code blocks now support:

### Highlighting words individually

```python highlight=strawberry,str
import strawberry


@strawberry.type
class X:
    name: str
```

### Highlighting lines

```python lines=1-4
import strawberry


@strawberry.type
class X:
    name: str
```

### Add notes to code comments

This is probably not implemented in the best way, but for now it works:

```python
import strawberry

#      ^^^^^^^^^^
#      This is a note about this line


# this is a standard comment
@strawberry.type
class X:
    name: str
```

<CodeNotes id="info">Strawberry is a cool library</CodeNotes>

### Split code blocks

You can show two different code blocks next to each other (useful when comparing
the GraphQL schema against the Python definition):

<CodeGrid>

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def ping(self) -> str:
        return "pong"
```

```graphql
type Query {
  ping: String!
}
```

</CodeGrid>

or when showing the request and response to a query:

```graphql+response
{
  ping
}
---
{
  "data": {
    "ping": "pong"
  }
}
```

## Call out blocks

<Tip>

This is a tip. Useful information is contained here.

</Tip>

<Note>

This is a note. Something that you should know about.

</Note>

<Warning>

This is a warning. Something that you should be careful about.

</Warning>

## Blockquote

> This is a quote

```mermaid
sequenceDiagram
    Alice ->> Bob: Hello Bob, how are you?
    Bob-->>John: How about you John?
    Bob--x Alice: I am good thanks!
    Bob-x John: I am good thanks!
    Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.

    Bob-->Alice: Checking with John...
    Alice->John: Yes... John, how are you?
```

---

### Breaking Changes (`docs/breaking-changes.md`)

---
title: List of breaking changes and deprecations
---

# List of breaking changes and deprecations

- [Version 0.328.0 - 28 September 2026](./breaking-changes/0.328.0.md)
- [Version 0.320.0 - 28 June 2026](./breaking-changes/0.320.0.md)
- [Version 0.288.0 - 28 December 2025](./breaking-changes/0.288.0.md)
- [Version 0.285.0 - 10 November 2025](./breaking-changes/0.285.0.md)
- [Version 0.283.0 - 6 October 2025](./breaking-changes/0.283.0.md)
- [Version 0.279.0 - 19 August 2025](./breaking-changes/0.279.0.md)
- [Version 0.278.1 - 5 August 2025](./breaking-changes/0.278.1.md)
- [Version 0.268.0 - 10 May 2025](./breaking-changes/0.268.0.md)
- [Version 0.251.0 - 21 November 2024](./breaking-changes/0.251.0.md)
- [Version 0.249.0 - 18 November 2024](./breaking-changes/0.249.0.md)
- [Version 0.243.0 - 25 September 2024](./breaking-changes/0.243.0.md)
- [Version 0.240.0 - 10 September 2024](./breaking-changes/0.240.0.md)
- [Version 0.236.0 - 17 July 2024](./breaking-changes/0.236.0.md)
- [Version 0.233.0 - 29 May 2024](./breaking-changes/0.233.0.md)
- [Version 0.217.0 - 18 December 2023](./breaking-changes/0.217.0.md)
- [Version 0.213.0 - 8 November 2023](./breaking-changes/0.213.0.md)
- [Version 0.180.0 - 31 May 2023](./breaking-changes/0.180.0.md)
- [Version 0.169.0 - 5 April 2023](./breaking-changes/0.169.0.md)
- [Version 0.159.0 - 22 February 2023](./breaking-changes/0.159.0.md)
- [Version 0.146.0 - 5 December 2022](./breaking-changes/0.146.0.md)

---

### Errors (`docs/errors.md`)

---
title: Errors
---

# Errors in strawberry

Strawberry has built-in errors for when something goes wrong with the creation
and usage of the schema.

It also provides a custom exception handler for improving how errors are printed
and to make it easier to find the exception source, for example the following
code:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello_world(self):
        return "Hello there!"


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

will show the following exception on the command line:

```text

  error: Missing annotation for field `hello_world`

       @ demo.py:7

     6 |     @strawberry.field
  ❱  7 |     def hello_world(self):
                 ^^^^^^^^^^^ resolver missing annotation
     8 |         return "Hello there!"


  To fix this error you can add an annotation, like so `def hello_world(...) -> str:`

  Read more about this error on https://errors.strawberry.rocks/missing-return-annotation

```

These errors are only enabled when `rich` and `libcst` are installed. You can
install Strawberry with errors enabled by running:

```shell
pip install "strawberry-graphql[cli]"
```

When Strawberry can't find the source code of the error, for example for code
run with `python -c` or in the interactive interpreter, the standard Python
traceback is shown instead.

If you want to disable the errors you can do so by setting the
`STRAWBERRY_DISABLE_RICH_ERRORS` environment variable to `1`.

---

### Extensions (`docs/extensions.md`)

---
title: Extensions
---

# Extensions

Extensions allow you, as an application developer, to customise the GraphQL
execution flow based on your needs. Strawberry provides multiple built in
extensions that allow you to extend the capability of your GraphQL server.

If you can't find what you need among the
[built-in extensions](#built-in-extensions), you can also build your own custom
extension based on a standard interface. Check out the
[schema extensions](./guides/custom-extensions.md) and
[field extensions](./guides/field-extensions.md) guides to find out more.

## Built-in extensions

<ExtensionsList />

---

### Faq (`docs/faq.md`)

---
title: FAQ
faq: true
---

# Frequently Asked Questions

## How can I hide a field from GraphQL?

Strawberry provides a `Private` type that can be used to hide fields from
GraphQL, for example, the following code:

```python
import strawberry


@strawberry.type
class User:
    name: str
    age: int
    password: strawberry.Private[str]


@strawberry.type
class Query:
    @strawberry.field
    def user(self) -> User:
        return User(name="Patrick", age=100, password="This is fake")


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

will result in the following schema:

```graphql
type Query {
  user: User!
}

type User {
  name: String!
  age: Int!
}
```

## How can I deal with circular imports?

In cases where you have circular imports, you can use `strawberry.lazy` to
resolve the circular imports, for example:

```python
# posts.py
from typing import TYPE_CHECKING, Annotated

import strawberry

if TYPE_CHECKING:
    from .users import User


@strawberry.type
class Post:
    title: str
    author: Annotated["User", strawberry.lazy(".users")]
```

For more information, see the [Lazy types](./types/lazy.md) documentation.

## Can I reuse Object Types with Input Objects?

Unfortunately not because, as the
[GraphQL spec](https://spec.graphql.org/June2018/#sec-Input-Objects) specifies,
there is a difference between Objects Types and Inputs types:

> The GraphQL Object type (ObjectTypeDefinition) defined above is inappropriate
> for re‐use here, because Object types can contain fields that define arguments
> or contain references to interfaces and unions, neither of which is
> appropriate for use as an input argument. For this reason, input objects have
> a separate type in the system.

And this is also true for Input types' fields: you can only use Strawberry Input
types or scalar.

See our [Input Types](./types/input-types.md) docs.

## Can I use asyncio with Strawberry and Django?

Yes, Strawberry provides an async view that can be used with Django, you can
Check [Async Django](./integrations/django.md#async-django) for more
information.

---

### Breaking Changes 0.146.0 (`docs/breaking-changes/0.146.0.md`)

---
title: 0.146.0 Breaking Changes
slug: breaking-changes/0.146.0
---

# v0.146.0 Breaking Changes - 5 December 2022

This release introduces a couple of breaking changes to the Sanic integration.

## `process_result` is now async and accepts the request as the first argument

If you customized the `process_result` function, you will need to update your
code to make it async and accept the request as the first argument.

For example:

```python
from strawberry.sanic.views import GraphQLView
from strawberry.http import GraphQLHTTPResponse, process_result
from strawberry.types import ExecutionResult
from sanic.request import Request
from graphql.error.graphql_error import format_error as format_graphql_error


class MyGraphQLView(GraphQLView):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        if result.errors:
            result.errors = [format_graphql_error(err) for err in result.errors]

        return process_result(data)
```

## `get_context` now receives also the response as the second argument

If you customized the `get_context` function, you will need to update your code
to accept the response as the second argument. The response argument allows you
to set cookies and other headers.

For example:

```python
from strawberry.sanic.views import GraphQLView
from strawberry.sanic.context import StrawberrySanicContext
from strawberry.http.temporal_response import TemporalResponse
from sanic.request import Request


class MyGraphQLView(GraphQLView):
    async def get_context(
        self, request: Request, response: TemporalResponse
    ) -> StrawberrySanicContext:
        return {"request": request, "response": response}
```

# Deprecations

## Context value is now a dictionary

The context value is now a dictionary instead of a custom class. This means that
you should access the context value using the `["key"]` syntax instead of the
`.key` syntax.

The `.key` syntax is still supported but will be removed in future releases.

---

### Breaking Changes 0.159.0 (`docs/breaking-changes/0.159.0.md`)

---
title: 0.159.0 Deprecations
slug: breaking-changes/0.159.0
---

# v0.159.0 Introduces changes how extension hooks are defined

This release changes how extension hooks are defined. The new style hooks are
more flexible and allow to run code before and after the execution.

The old style hooks are still supported but will be removed in future releases.

# How to upgrade

## Before:

```python
class MyExtension(Extension):
    def on_executing_start(self): ...

    def on_executing_end(self): ...
```

## After

```python
class MyExtension(Extension):
    def on_execute(self):
        # code before the execution starts
        yield
        # code after the execution ends
```

# Migration guide

See the following table for a mapping between the old and new hooks.

| Old hook            | New hook     |
| ------------------- | ------------ |
| on_request_start    | on_operation |
| on_request_end      | on_operation |
| on_validation_start | on_validate  |
| on_validation_end   | on_validate  |
| on_parsing_start    | on_parse     |
| on_parsing_end      | on_parse     |
| on_executing_start  | on_execute   |
| on_executing_end    | on_execute   |

---

### Breaking Changes 0.169.0 (`docs/breaking-changes/0.169.0.md`)

---
title: 0.169.0 Breaking changes
slug: breaking-changes/0.169.0
---

# v0.169.0 Introduces a couple of breaking changes in the HTTP integrations

## Flask

Both `get_root_value` and `get_context` now receive the request as a parameter.

If you're customizing these methods you can change the signature to:

```python
def get_root_value(self, request: Request) -> Any: ...


def get_context(self, request: Request, response: Response) -> Any: ...
```

The same is true for the async version of the view.

## Sanic

The `get_root_value` method now receives the request as a parameter and it is
async.

If you're customizing this method you can change the signature to:

```python
async def get_root_value(self, request: Request) -> Any: ...
```

---

### Breaking Changes 0.180.0 (`docs/breaking-changes/0.180.0.md`)

---
title: 0.180.0 Breaking changes
slug: breaking-changes/0.180.0
---

# v0.180.0 introduces a breaking change for the Django Channels HTTP integration

The context object is now a `dict`. This means that you should access the
context value using the `["key"]` syntax instead of the `.key` syntax.

For the HTTP integration, there is also no `ws` key anymore and `request` is a
custom request object containing the full request instead of a
`GraphQLHTTPConsumer` instance. If you need to access the `GraphQLHTTPConsumer`
instance in a HTTP connection, you can access it via
`info.context["request"].consumer`.

For the WebSockets integration, the context keys did not change, e.g. the values
for `info.context["ws"]`, `info.context["request"]` and
`info.context["connection_params"]` are the same as before.

If you still want to use the `.key` syntax, you can override `get_context()` to
return a custom dataclass there. See the Channels integration documentation for
an example.

---

### Breaking Changes 0.213.0 (`docs/breaking-changes/0.213.0.md`)

---
title: 0.213.0 Deprecation
slug: breaking-changes/0.213.0
---

# v0.213.0 introduces a deprecation for `graphiql` parameter

All HTTP integration now will use `graphql_ide` instead of `graphiql` parameter.
If you're not using the `graphiql` parameter, you can safely ignore this
deprecation.

If you're using the `graphiql` parameter, you should change it to `graphql_ide`
instead.

Here's an example of the changes:

```diff
-graphql_app = GraphQLRouter(schema, graphiql=True)
+graphql_app = GraphQLRouter(schema, graphql_ide="graphiql")

-graphql_app = GraphQLRouter(schema, graphiql=False)
+graphql_app = GraphQLRouter(schema, graphql_ide=None)
```

---

### Breaking Changes 0.217.0 (`docs/breaking-changes/0.217.0.md`)

---
title: 0.217 Breaking Changes
slug: breaking-changes/0.217.0
---

# v0.217.0 changes how kwargs are passed to `has_permission` method

Previously the `kwargs` argument keys for the `has_permission` method were using
camel casing (depending on your schema configuration), now they will always
follow the python name defined in your resolvers.

```python
class IsAuthorized(BasePermission):
    message = "User is not authorized"

    def has_permission(
        self, source, info, **kwargs: typing.Any
    ) -> bool:  # pragma: no cover
        # kwargs will have a key called "a_key"
        # instead of `aKey`

        return False


@strawberry.type
class Query:
    @strawberry.field(permission_classes=[IsAuthorized])
    def name(self, a_key: str) -> str:  # pragma: no cover
        return "Erik"
```

---

### Breaking Changes 0.233.0 (`docs/breaking-changes/0.233.0.md`)

---
title: 0.233.0 Breaking Changes
slug: breaking-changes/0.233.0
---

# v0.233.0 changes the `info` argument in `resolve_reference` in Federation

In this release we have updated the `info` object passed to the
`resolve_reference` function in Federation to be a `strawberry.Info` object
instead of the one coming from GraphQL-core.

If you need to access the original `info` object you can do so by accessing the
`_raw_info` attribute.

```python
import strawberry


@strawberry.federation.type(keys=["upc"])
class Product:
    upc: str

    @classmethod
    def resolve_reference(cls, info: strawberry.Info, upc: str) -> "Product":
        # Access the original info object
        original_info = info._raw_info

        return Product(upc=upc)
```

---

### Breaking Changes 0.236.0 (`docs/breaking-changes/0.236.0.md`)

---
title: 0.236.0 Breaking Changes
slug: breaking-changes/0.236.0
---

# v0.236.0 changes some of the imports

This release changes the location of some files in the codebase, this is to make
the codebase more organized and easier to navigate.

Technically most of these changes should not affect you, but if you were
importing some of the files directly you will need to update the imports.

We created a codemod to help you with that, feel free to try and submit bugs if
we missed something.

```bash
strawberry upgrade update-imports
```

---

### Breaking Changes 0.240.0 (`docs/breaking-changes/0.240.0.md`)

---
title: 0.240.0 Breaking Changes
slug: breaking-changes/0.240.0
---

# v0.240.0 updates `Schema.subscribe`'s signature

In order to support schema extensions in subscriptions and errors that can be
raised before the execution of the subscription, we had to update the signature
of `Schema.subscribe`.

Previously it was:

```python
async def subscribe(
    self,
    query: str,
    variable_values: Optional[Dict[str, Any]] = None,
    context_value: Optional[Any] = None,
    root_value: Optional[Any] = None,
    operation_name: Optional[str] = None,
) -> Union[AsyncIterator[GraphQLExecutionResult], GraphQLExecutionResult]:
```

Now it is:

```python
async def subscribe(
    self,
    query: Optional[str],
    variable_values: Optional[Dict[str, Any]] = None,
    context_value: Optional[Any] = None,
    root_value: Optional[Any] = None,
    operation_name: Optional[str] = None,
) -> Union[AsyncGenerator[ExecutionResult, None], PreExecutionError]:
```

---

### Breaking Changes 0.243.0 (`docs/breaking-changes/0.243.0.md`)

---
title: 0.243.0 Breaking Changes
slug: breaking-changes/0.243.0
---

# v0.243.0 Breaking Changes

Release v0.243.0 comes with two breaking changes regarding multipart file
uploads and Django CSRF protection.

## Multipart uploads disabled by default

Previously, support for uploads via the
[GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec)
was enabled by default. This implicitly required Strawberry users to consider
the
[security implications outlined in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security).
Given that most Strawberry users were likely not aware of this, we're making
multipart file upload support stictly opt-in via a new
`multipart_uploads_enabled` view settings.

To enable multipart upload support for your Strawberry view integration, please
follow the updated integration guides and enable appropriate security
measurements for your server.

## Django CSRF protection enabled

Previously, the Strawberry Django view integration was internally exempted from
Django's built-in CSRF protection (i.e, the `CsrfViewMiddleware` middleware).
While this is how many GraphQL APIs operate, implicitly addded exemptions can
lead to security vulnerabilities. Instead, we delegate the decision of adding an
CSRF exemption to users now.

Note that having the CSRF protection enabled on your Strawberry Django view
potentially requires all your clients to send an CSRF token with every request.
You can learn more about this in the official Django
[Cross Site Request Forgery protection documentation](https://docs.djangoproject.com/en/dev/ref/csrf/).

To restore the behaviour of the integration before this release, you can add the
`csrf_exempt` decorator provided by Django yourself:

```python
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from strawberry.django.views import GraphQLView

from api.schema import schema

urlpatterns = [
    path("graphql/", csrf_exempt(GraphQLView.as_view(schema=schema))),
]
```

---

### Breaking Changes 0.249.0 (`docs/breaking-changes/0.249.0.md`)

---
title: 0.249.0 Breaking Changes
slug: breaking-changes/0.249.0
---

# v0.249.0 Breaking Changes

After a year-long deprecation period, the `SentryTracingExtension` has been
removed in favor of the official Sentry SDK integration.

To migrate, remove the `SentryTracingExtension` from your Strawberry schema and
then follow the
[official Sentry SDK integration guide](https://docs.sentry.io/platforms/python/integrations/strawberry/).

---

### Breaking Changes 0.251.0 (`docs/breaking-changes/0.251.0.md`)

---
title: 0.251.0 Breaking Changes
slug: breaking-changes/0.251.0
---

# v0.251.0 Breaking Changes

We slightly changed the signature of the `encode_json` method used to customize
the JSON encoder used by our HTTP views.

Originally, the method was only meant to encode HTTP response data. Starting
with this release, it's also used to encode WebSocket messages.

Previously, the method signature was:

```python
def encode_json(self, response_data: GraphQLHTTPResponse) -> str: ...
```

To upgrade your code, change the method signature to the following and make sure
your method can handle the same inputs as the built-in `json.dumps` method:

```python
def encode_json(self, data: object) -> str: ...
```

---

### Breaking Changes 0.268.0 (`docs/breaking-changes/0.268.0.md`)

---
title: 0.268.0 Breaking Changes
slug: breaking-changes/0.268.0
---

# v0.268.0

This release changes GlobalIDs to ID in the GraphQL schema, now instead of
having `GlobalID` as type when using `relay.Node` you'll get `ID`.

The runtime behaviour is still the same.

If you need to use the previous behaviour you can use the following config:

```python
schema = strawberry.Schema(
    query=Query, config=StrawberryConfig(relay_use_legacy_global_id=True)
)
```

This release renames the generated type from `GlobalID` to `ID` in the GraphQL
schema.

This means that when using `relay.Node`, like in this example:

```python
@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[int]
    name: str
```

You'd create a GraphQL type that looks like this:

```graphql
type Fruit implements Node {
  id: ID!
  name: String!
}
```

while previously you'd get this:

```graphql
type Fruit implements Node {
  id: GlobalID!
  name: String!
}
```

The runtime behaviour is still the same, so if you want to use `GlobalID` in
Python code, you can still do so, for example:

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    @staticmethod
    async def update_fruit_weight(id: relay.GlobalID, weight: float) -> Fruit:
        # while `id` is a GraphQL `ID` type, here is still an instance of `relay.GlobalID`
        fruit = await id.resolve_node(info, ensure_type=Fruit)
        fruit.weight = weight
        return fruit
```

If you want to revert this change, and keep `GlobalID` in the schema, you can
use the following configuration:

```python
schema = strawberry.Schema(
    query=Query, config=StrawberryConfig(relay_use_legacy_global_id=True)
)
```

---

### Breaking Changes 0.278.1 (`docs/breaking-changes/0.278.1.md`)

---
title: 0.278.1 Breaking Changes
slug: breaking-changes/0.278.1
---

# v0.278.1 Breaking Changes

This release removes `strawberry.http.exceptions`. HTTP-related exceptions can
now be imported directly from the `lia` package.

For example, instead of:

```python
from strawberry.http.exceptions import HTTPException
```

Now you need to do:

```python
from lia import HTTPException
```

---

### Breaking Changes 0.279.0 (`docs/breaking-changes/0.279.0.md`)

---
title: 0.279.0 Breaking Changes
slug: breaking-changes/0.279.0
---

# v0.279.0 Breaking Changes

This release changes the `strawberry.Maybe` type definition to provide a more
consistent and intuitive API for handling optional fields.

## What Changed

The `Maybe` type definition has been changed from:

```python
Maybe: TypeAlias = Union[Some[Union[T, None]], None]
```

to:

```python
Maybe: TypeAlias = Union[Some[T], None]
```

## Impact on Your Code

### Type Annotations

If you were using `Maybe[T]` and expecting to handle explicit `null` values, you
now need to explicitly declare this with `Maybe[T | None]`:

```python
# Before (0.278.0 and earlier)
field: strawberry.Maybe[str]  # Could handle Some(None)

# After (0.279.0+)
field: strawberry.Maybe[str]  # Only handles Some("value") or None (absent)
field: strawberry.Maybe[str | None]  # Handles Some("value"), Some(None), or None
```

### Runtime Behavior

The runtime behavior changes to provide more consistent field checking:

- `Maybe[str]` now represents "field present with non-null value" or "field
  absent"
- `Maybe[str | None]` represents "field present with value", "field present but
  null", or "field absent"

This means `Maybe[str]` can no longer receive explicit `null` values - they will
cause a validation error.

### Consistent Field Checking

This change provides a single, consistent way to check if a field was provided,
regardless of whether the field allows null values:

```python
@strawberry.input
class UpdateUserInput:
    # Can be provided with a value or not provided at all
    name: strawberry.Maybe[str]

    # Can be provided with a value, provided as null, or not provided at all
    phone: strawberry.Maybe[str | None]


@strawberry.mutation
def update_user(input: UpdateUserInput) -> User:
    # Same checking pattern for both fields
    if input.name is not None:  # Field was provided
        user.name = input.name.value  # Type checker knows this is str

    if input.phone is not None:  # Field was provided
        user.phone = input.phone.value  # Type checker knows this is str | None
```

The key benefit is that `if field is not None` now consistently means "field was
provided" for all Maybe fields.

## Migration

### Automatic Migration

Strawberry provides a codemod to automatically update your code:

```bash
strawberry upgrade maybe-optional
```

The codemod will automatically convert `Maybe[T]` to `Maybe[T | None]` to
maintain the previous behavior.

### Manual Migration

Review your `Maybe` usage and decide whether you need the union type:

```python
# If you only need "present" vs "absent" (most common case)
field: strawberry.Maybe[str]

# If you need "present with value", "present but null", and "absent"
field: strawberry.Maybe[str | None]
```

## Why This Change?

After extensive discussion, we decided that changing `Maybe` to `Some[T] | None`
(instead of `Some[T | None] | None`) provides the best developer experience
because:

1. **Consistent field checking**: You can always use `if field is not None:` to
   check if a field was provided, regardless of whether the field allows null
   values

2. **Preserves existing behavior**: You can still get the previous behavior by
   using `Maybe[T | None]` when you need to handle explicit nulls

3. **Better type safety**: `Maybe[str]` now properly indicates that the field
   cannot be null, while `Maybe[str | None]` explicitly allows nulls

4. **Cleaner API**: There's now "one true way" to check if a field was provided,
   making the API more intuitive

The new approach provides both simplicity for common cases and flexibility for
complex scenarios where null handling is needed.

## Need Help?

- See the [Maybe documentation](../types/maybe.md) for comprehensive usage
  examples
- Check the
  [migration guide](../types/maybe.md#migration-from-previous-versions) for
  detailed migration instructions
- If you encounter issues, please
  [report them on GitHub](https://github.com/strawberry-graphql/strawberry/issues)

---

### Breaking Changes 0.283.0 (`docs/breaking-changes/0.283.0.md`)

---
title: 0.283.0 Breaking Changes
slug: breaking-changes/0.283.0
---

# v0.283.0 Breaking Changes

In this release, we renamed the `strawberry server` command to `strawberry dev`
to better reflect its purpose as a development server. The old command will
print a deprecation warning for now and will be removed in a future release.

We also deprecated the `strawberry-graphql[debug-server]` extra in favor of
`strawberry-graphql[cli]`. Please update your dependencies accordingly.

## Migrate Dependencies

If you were using the `strawberry-graphql[debug-server]` extra in your project,
please update it to `strawberry-graphql[cli]`.

## Migrate Scripts

If you previously used the command:

```bash
strawberry server
```

Please update it to:

```bash
strawberry dev
```

---

### Breaking Changes 0.285.0 (`docs/breaking-changes/0.285.0.md`)

---
title: 0.285.0 Breaking Changes
slug: breaking-changes/0.285.0
---

# v0.285.0 Breaking Changes

This release removes support for Apollo Federation v1 and updates the federation
API to always use Federation v2.

## What Changed

The `enable_federation_2` parameter has been removed and replaced with
`federation_version`. Federation v2 is now always enabled, with version 2.11 as
the default.

```python
# Before (0.284.x and earlier)
schema = strawberry.federation.Schema(
    query=Query,
    enable_federation_2=True,  # Opt-in to Federation 2
)

# After (0.285.0+)
schema = strawberry.federation.Schema(
    query=Query,
    federation_version="2.11",  # Defaults to "2.11", always Federation 2
)
```

## Impact on Your Code

### Federation v2 Users

If you were already using `enable_federation_2=True`, you can remove that
parameter:

```python
# Before
schema = strawberry.federation.Schema(query=Query, enable_federation_2=True)

# After
schema = strawberry.federation.Schema(query=Query)
```

Your schemas will continue to work without changes and will now default to
Federation v2.11.

### Federation v1 Users

If you were using Federation v1 (without `enable_federation_2`), you **must**
migrate to Federation v2. Apollo Federation v1 is no longer supported by
Strawberry.

Federation v2 provides better schema composition and additional features. Most
v1 schemas can be migrated with minimal changes:

```python
# Before (Federation v1)
schema = strawberry.federation.Schema(query=Query)

# After (Federation v2)
schema = strawberry.federation.Schema(query=Query)  # Now uses v2.11
```

Key differences in Federation v2:

1. **No `extend` keyword needed**: Types no longer need to be marked as
   extensions
2. **No `@external` required**: The `@key` directive alone is sufficient in most
   cases
3. **`@shareable` directive**: Use this to indicate fields that can be resolved
   by multiple subgraphs
4. **`@link` directive**: Automatically added to declare federation spec version

See the
[Apollo Federation v2 migration guide](https://www.apollographql.com/docs/federation/federation-2/moving-to-federation-2/)
for more details.

## Specifying Federation Version

You can now specify which Federation v2 version to use:

```python
schema = strawberry.federation.Schema(
    query=Query,
    federation_version="2.5",  # Use a specific version
)
```

Supported versions: 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10, 2.11

This is useful if you need to ensure compatibility with a specific Apollo Router
or Gateway version, or if you want to avoid using newer directives.

### Version Validation

Strawberry validates that directives are compatible with your chosen federation
version:

```python
from strawberry.federation.schema_directives import Cost


@strawberry.federation.type
class Product:
    name: str = strawberry.federation.field(
        directives=[Cost(weight=10)]  # Requires v2.9+
    )


# This will raise an error because @cost requires v2.9+
schema = strawberry.federation.Schema(
    query=Query,
    federation_version="2.5",  # Too old for @cost
)
```

## Why This Change?

1. **Apollo Federation v1 is deprecated**: Apollo has moved to Federation v2 as
   the standard
2. **Simpler API**: Removes the boolean flag in favor of explicit version
   control
3. **Better features**: Federation v2 provides improved schema composition and
   new directives
4. **Version control**: Users can now specify exact federation versions for
   compatibility

## Migration Steps

### Step 1: Check Your Current Usage

If you're using `enable_federation_2=False` or not setting it at all, you're
using Federation v1 and need to migrate.

### Step 2: Remove Federation v1 Code

```python
# Remove this parameter
schema = strawberry.federation.Schema(
    query=Query,
    enable_federation_2=True,  # Remove this line
)
```

### Step 3: Update Federation v1 Patterns

If you were using Federation v1 patterns like `extend=True` and explicit
`@external` fields, you can simplify:

```python
# Before (Federation v1)
@strawberry.federation.type(keys=["id"], extend=True)
class Product:
    id: strawberry.ID = strawberry.federation.field(external=True)
    reviews: list[Review]


# After (Federation v2)
@strawberry.federation.type(keys=["id"])
class Product:
    id: strawberry.ID
    reviews: list[Review]
```

### Step 4: Test Your Schema

Run your schema composition and tests to ensure everything works correctly with
Federation v2.

## Need Help?

- See the [Federation guide](../guides/federation.md) for comprehensive usage
  examples
- Review the
  [Apollo Federation v2 documentation](https://www.apollographql.com/docs/federation/federation-2/new-in-federation-2/)
- If you encounter issues, please
  [report them on GitHub](https://github.com/strawberry-graphql/strawberry/issues)

---

### Breaking Changes 0.288.0 (`docs/breaking-changes/0.288.0.md`)

---
title: 0.288.0 Breaking Changes
slug: breaking-changes/0.288.0
---

# v0.288.0 Breaking Changes

This release deprecates passing a class (or type) to `strawberry.scalar()`. Use
`scalar_map` in `StrawberryConfig` instead.

## Deprecated: `strawberry.scalar(cls, ...)`

The pattern of wrapping a type with `strawberry.scalar()` is deprecated:

```python
# Deprecated
Base64 = strawberry.scalar(
    NewType("Base64", bytes),
    serialize=lambda v: base64.b64encode(v).decode(),
    parse_value=lambda v: base64.b64decode(v),
)
```

Instead, use `scalar_map` in `StrawberryConfig`:

```python
# Recommended
from typing import NewType
from strawberry.schema.config import StrawberryConfig

Base64 = NewType("Base64", bytes)

schema = strawberry.Schema(
    query=Query,
    config=StrawberryConfig(
        scalar_map={
            Base64: strawberry.scalar(
                name="Base64",
                serialize=lambda v: base64.b64encode(v).decode(),
                parse_value=lambda v: base64.b64decode(v),
            )
        }
    ),
)
```

This approach provides better type checking support because your custom scalar
stays a proper type that type checkers (mypy, pyright, ty) can understand. The
previous pattern of wrapping types with `strawberry.scalar()` returned a
`ScalarWrapper` object, which type checkers could not use as a valid type
annotation, causing errors like "Variable not allowed in type expression".

## Removed: Scalar wrapper exports

The scalar wrapper exports (`Date`, `DateTime`, `Time`, `Decimal`, `UUID`,
`Void`) from `strawberry.schema.types.base_scalars` have been removed. Use
standard Python types directly instead (`datetime.date`, `datetime.datetime`,
etc.).

A codemod is available: `strawberry upgrade replace-scalar-wrappers .`

---

### Breaking Changes 0.320.0 (`docs/breaking-changes/0.320.0.md`)

---
title: 0.320.0 Breaking Changes
slug: breaking-changes/0.320.0
---

# v0.320.0 makes multipart subscriptions opt-in

This release adds support for
[GraphQL subscriptions over Server-Sent Events (SSE)](../general/subscriptions.md#using-sse-subscriptions).
As part of that work, streaming transports are now selected from your
integration's `subscription_protocols`, which changes how multipart
subscriptions are enabled.

## Multipart subscriptions are now opt-in

Previously, multipart subscriptions were enabled unconditionally: any request
sent with an `Accept: multipart/mixed` header was served as a multipart
subscription stream, regardless of the `subscription_protocols` you configured.

Now a streaming transport (multipart subscriptions or SSE) is only active when
its protocol is listed in `subscription_protocols`. The default
(`graphql-transport-ws` and `graphql-ws`) does not include the multipart
protocol, so if you relied on multipart subscriptions you need to enable them
explicitly by adding `MULTIPART_SUBSCRIPTION_PROTOCOL`:

```python
from strawberry.asgi import GraphQL
from strawberry.subscriptions import (
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
    MULTIPART_SUBSCRIPTION_PROTOCOL,
)

app = GraphQL(
    schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        MULTIPART_SUBSCRIPTION_PROTOCOL,
    ],
)
```

The same applies to SSE, which is enabled with `GRAPHQL_SSE_PROTOCOL`. Both
constants are importable from `strawberry.subscriptions`.

If you do not use multipart subscriptions, no changes are required.

---

### Breaking Changes 0.328.0 (`docs/breaking-changes/0.328.0.md`)

---
title: 0.328.0 Breaking Changes
slug: breaking-changes/0.328.0
---

# v0.328.0 requires graphql-core 3.3

Strawberry now requires `graphql-core>=3.3.0,<3.4.0`. Support for graphql-core
3.2 and for the 3.3 pre-releases (`3.3.0a*`, `3.3.0b*` and `3.3.0rc*`) has been
removed.

## Upgrading

Upgrade graphql-core together with Strawberry:

```shell
pip install --upgrade strawberry-graphql "graphql-core>=3.3.0"
```

Some packages still pin `graphql-core<3.3`, most notably `graphene` and
`graphql-relay`. If they're installed in the same environment as Strawberry,
your installer won't be able to resolve the new requirement until they support
graphql-core 3.3.

## Behavior changes coming from graphql-core 3.3

graphql-core 3.3 changes some user-visible output, which Strawberry now always
uses:

- Error messages for invalid variables and arguments are worded differently, for
  example `Variable '$value' has invalid value: ...` instead of
  `Variable '$value' got invalid value ...`. Update any tests or clients that
  match on the exact message.
- Printed schemas format some default values differently, for example input
  object defaults are printed with spaces inside the braces (`{ a: "hi" }`
  instead of `{a: "hi"}`).

## Custom execution context classes

graphql-core 3.3 replaces `graphql.ExecutionContext` with
`graphql.execution.Executor`. If you pass a custom `execution_context_class` to
your schema, subclass
`strawberry.schema.schema.StrawberryGraphQLCoreExecutionContext` so that
Strawberry features such as `info.input_extensions` and `@defer`/`@stream` keep
working:

```python
import strawberry
from strawberry.schema.schema import StrawberryGraphQLCoreExecutionContext


class MyExecutionContext(StrawberryGraphQLCoreExecutionContext): ...


schema = strawberry.Schema(query=Query, execution_context_class=MyExecutionContext)
```

## Removed `IS_GQL_32` and `IS_GQL_33`

The internal `strawberry.utils.IS_GQL_32` and `strawberry.utils.IS_GQL_33`
constants have been removed, since only graphql-core 3.3 is supported.

---

### Cli Locate Definition (`docs/cli/locate-definition.md`)

---
title: Locate definition
---

# Locate definition

Strawberry provides a CLI command `strawberry locate-definition` that allows you
to find the source location of a definition within the schema.

You can provide either a model name or a model name and field name, e.g.:

```
strawberry locate-definition path.to.schema:schema ObjectName
```

```
strawberry locate-definition path.to.schema:schema ObjectName.fieldName
```

If found, the result will be printed to the console in the form of
`path/to/file.py:line:column`, for example: `src/models/user.py:45:12`.

## Using with VS Code's Relay extension

You can use this command with the go to definition feature of VS Code's Relay
extension (configured via the `relay.pathToLocateCommand` setting).

You can create a script to do this, for example:

```sh
# ./locate-definition.sh
strawberry locate-definition path.to.schema:schema "$2"
```

Then, you can set the `relay.pathToLocateCommand` setting to the path of the
script, e.g.:

```json
"relay.pathToLocateCommand": "./locate-definition.sh"
```

You can then use the go to definition feature to navigate to the definition of a
model or field.

---

### Codegen Query Codegen (`docs/codegen/query-codegen.md`)

---
title: Codegen
experimental: true
---

# Query codegen

Strawberry supports code generation for GraphQL queries.

<Note>

Schema codegen will be supported in future releases. We are testing the query
codegen in order to come up with a nice API.

</Note>

Let's assume we have the following GraphQL schema built with Strawberry:

```python
from typing import List

import strawberry


@strawberry.type
class Post:
    id: strawberry.ID
    title: str


@strawberry.type
class User:
    id: strawberry.ID
    name: str
    email: str

    @strawberry.field
    def post(self) -> Post:
        return Post(id=self.id, title=f"Post for {self.name}")


@strawberry.type
class Query:
    @strawberry.field
    def user(self, info) -> User:
        return User(id=strawberry.ID("1"), name="John", email="abc@bac.com")

    @strawberry.field
    def all_users(self) -> List[User]:
        return [
            User(id=strawberry.ID("1"), name="John", email="abc@bac.com"),
        ]


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

and we want to generate types based on the following query:

```graphql
query MyQuery {
  user {
    post {
      title
    }
  }
}
```

With the following command:

```shell
strawberry codegen --schema schema --output-dir ./output -p python query.graphql
```

We'll get the following output inside `output/query.py`:

```python
class MyQueryResultUserPost:
    title: str


class MyQueryResultUser:
    post: MyQueryResultUserPost


class MyQueryResult:
    user: MyQueryResultUser
```

## Why is this useful?

Query code generation is usually used to generate types for clients using your
GraphQL APIs.

Tools like [GraphQL Codegen](https://www.graphql-code-generator.com/) exist in
order to create types and code for your clients. Strawberry's codegen feature
aims to address the similar problem without needing to install a separate tool.

## Plugin system

Strawberry's codegen supports plugins, in the example above for example, we are
using the `python` plugin. To pass more plugins to the codegen tool, you can use
the `-p` flag, for example:

```shell
strawberry codegen --schema schema --output-dir ./output -p python -p typescript query.graphql
```

the plugin can be specified as a python path.

### Custom plugins

The interface for plugins looks like this:

```python
from strawberry.codegen import CodegenPlugin, CodegenFile, CodegenResult
from strawberry.codegen.types import GraphQLType, GraphQLOperation


class QueryCodegenPlugin:
    def __init__(self, query: Path) -> None:
        """Initialize the plugin.

        The singular argument is the path to the file that is being processed by this plugin.
        """
        self.query = query

    def on_start(self) -> None: ...

    def on_end(self, result: CodegenResult) -> None: ...

    def generate_code(
        self, types: List[GraphQLType], operation: GraphQLOperation
    ) -> List[CodegenFile]:
        return []
```

- `on_start` is called before the codegen starts.
- `on_end` is called after the codegen ends and it receives the result of the
  codegen. You can use this to format code, or add licenses to files and so on.
- `generated_code` is called when the codegen starts and it receives the types
  and the operation. You cans use this to generate code for each type and
  operation.

### Console plugin

There is also a plugin that helps to orchestrate the codegen process and notify
the user about what the current codegen process is doing.

The interface for the ConsolePlugin looks like:

```python
class ConsolePlugin:
    def __init__(self, output_dir: Path):
        """Initialize the plugin and tell it where the output should be written."""
        ...

    def before_any_start(self) -> None:
        """This method is called before any plugins have been invoked or any queries have been processed."""
        ...

    def after_all_finished(self) -> None:
        """This method is called after the full code generation is complete.

        It can be used to report on all the things that have happened during the codegen.
        """
        ...

    def on_start(self, plugins: Iterable[QueryCodegenPlugin], query: Path) -> None:
        """This method is called before any of the individual plugins have been started."""
        ...

    def on_end(self, result: CodegenResult) -> None:
        """This method typically persists the results from a single query to the output directory."""
        ...
```

---

### Codegen Schema Codegen (`docs/codegen/schema-codegen.md`)

---
title: Schema codegen
---

# Schema codegen

Strawberry supports code generation from SDL files.

Let's assume we have the following SDL file:

```graphql
type Query {
  user: User
}

type User {
  id: ID!
  name: String!
}
```

by running the following command:

```shell
strawberry schema-codegen schema.graphql
```

we'll get the following output:

```python
import strawberry


@strawberry.type
class Query:
    user: User | None


@strawberry.type
class User:
    id: strawberry.ID
    name: str


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

---

### Concepts Async (`docs/concepts/async.md`)

---
title: Async
---

# Async

Async is a concurrent programming design that has been supported in Python since
version 3.4. To learn more about async in Python refer to
[Real Python’s Async walkthrough](https://realpython.com/async-io-python/).

Strawberry supports both async and non async resolvers, so you can mix and match
them in your code. Here’s an example of an async resolver:

```python
import asyncio
import strawberry


async def resolve_hello(root) -> str:
    await asyncio.sleep(1)

    return "Hello world"


@strawberry.type
class Query:
    hello: str = strawberry.field(resolver=resolve_hello)


schema = strawberry.Schema(Query)
```

---

### Concepts Typings (`docs/concepts/typings.md`)

---
title: Type hints
---

# Type hints

Type hints are a modern feature of Python available since 3.5 whose existence is
heavily influenced by the features of type-safe languages such as Rust. To learn
more about type hints in Python, see
[Real Python’s Type hinting walkthrough](https://realpython.com/lessons/type-hinting/).

When using Strawberry to build graphQL APIs, as was shown in
[Schema basics](https://strawberry.rocks/docs/general/schema-basics), type hints
are required within classes decorated by `@strawberry.type` &
`@strawberry.input` and functions decorated by `@strawberry.field` &
`strawberry.mutation`. These type hints are sourced as the keywords `str`,
`int`, `float`, and from packages imported directly from the Python standard
libraries `typing`, that has been available since Python 3.5, `datetime`, and
`decimal`.

## Mapping to graphQL types

The complete mapping of the required type hints for the relevant graphQL types
is as follows:

| GraphQL       | Python                         |
| ------------- | ------------------------------ |
| `ID`          | `strawberry.ID`                |
| `String`      | `str`                          |
| `Integer`     | `int`                          |
| `Float`       | `float`                        |
| `Decimal`     | `decimal.Decimal`              |
| `Array`, `[]` | `typing.List` or `list`        |
| `Union`       | `typing.Union` or `\|`         |
| `Nullable`    | `typing.Optional` or `None \|` |
| `Date`        | `datetime.date`                |
| `Datetime`    | `datetime.datetime`            |
| `Time`        | `datetime.time`                |

where `typing`, `datetime`, and `decimal` are all part of the Python standard
library. There is also `typing.Dict` that possesses no mapping since it is the
entire structure of the graphQL query itself that is a dictionary.

There are a few different ways in which these Python type hints can be used to
express the required Strawberry graphQL type annotation.

- Annotate a list of types with `list[Type]`.
- The annotation `|` is shorthand for `typing.Union[]`, allowing either of
  `typing.Union[TypeA, TypeB]` or `TypeA | TypeB` interchangably.
- The annotation `typing.Optional[Type]` is shorthand for
  `typing.Union[None, Type]`, which is itself equivalent to `None | Type`.

## Example

A complete example of this, extending upon
[Schema basics](https://strawberry.rocks/docs/general/schema-basics), might be
the following:

```python
import datetime
import decimal
from typing import List, Optional

import strawberry

BOOKS_LOOKUP = {
    "Frank Herbert": [
        {
            "title": "Dune",
            "date_published": "1965-08-01",
            "price": "5.99",
            "isbn": 9780801950773,
        }
    ],
}


@strawberry.type
class Book:
    title: str
    author: "Author"
    date_published: datetime.date
    price: decimal.Decimal
    isbn: str


def get_books_by_author(root: "Author") -> List["Book"]:
    stored_books = BOOKS_LOOKUP[root.name]

    return [
        Book(
            title=book.get("title"),
            author=root,
            date_published=book.get("date_published"),
            price=book.get("price"),
            isbn=book.get("isbn"),
        )
        for book in stored_books
    ]


@strawberry.type
class Author:
    name: str
    books: List[Book] = strawberry.field(resolver=get_books_by_author)


@strawberry.type
class Group:
    name: Optional[str]  # groups of authors don't necessarily have names
    authors: List[Author]

    @strawberry.field
    def books(self) -> List[Book]:
        books = []

        for author in self.authors:
            books += get_books_by_author(author)

        return books
```

- `self` within a resolver's definition, whether decorated as
  `@strawberry.field` or `@strawberry.mutation`, never needs a type hint because
  it can be inferred.
- `Optional` is the way to tell Strawberry that a field is nullable. Without it,
  every field is assumed to be non-null. This is in contrast to graphene wherein
  every field is assumed nullable unless `required=True` is supplied.
- Type hinting doesn't stop at being a requirement for Strawberry to function,
  it is also immensely helpful for collaborating developers. By specifying the
  type of `stored_books` in `get_books_by_author`, an IDE equipped with PyLance
  will be able to infer that `book` within the list comprehension is a
  dictionary and so will understand that `.get()` is a method function of the
  `dict` class. This helps the readability and maintainability of written code.

## Motivation

Python, much like Javascript and Ruby, is a _dynamically typed_ language that
allows for high-level programming where the fundamental types of variables, e.g.
integers, arrays, hash-maps, _etc._, are understood by the machine at _runtime_
through Just-in-Time compilation.

Yet, much like the low-level languages of C, Java, and Rust, the graphQL query
language is _statically typed_ since the data types defined by the schema must
be known prior to compiling the API code in order to define a definite schema to
query against.

In the low-level _statically typed_ languages mentioned above, every function
must have the types of both their arguments and returns explicitly declared so
that the compiler can interpret their behaviours correctly and ensure type
safety and consistency.

Strawberry takes inspiration from these languages by requiring that all of its
types, fields, resolvers, and mutations declare the types of their arguments and
returns. Through this, the schema is generated in a standard and efficient way
that aligns with the style-direction of Python and programming as a whole.

---

### Editors Mypy (`docs/editors/mypy.md`)

---
title: Mypy
---

# Mypy

Strawberry works with [Mypy](https://mypy.readthedocs.io/en/stable/) out of the
box thanks to
[`dataclass_transform`](https://typing.readthedocs.io/en/latest/spec/dataclasses.html#dataclass-transform).
No plugin is needed for standard Strawberry types, inputs, interfaces, enums,
scalars, or unions.

## Pydantic integration

If you use `strawberry.experimental.pydantic`, add **both** the pydantic and
strawberry plugins to your mypy configuration:

```ini
[mypy]
plugins = pydantic.mypy, strawberry.ext.mypy_plugin
```

Or in `pyproject.toml`:

```toml
[tool.mypy]
plugins = ["pydantic.mypy", "strawberry.ext.mypy_plugin"]
```

The strawberry plugin synthesises `__init__`, `to_pydantic()` and
`from_pydantic()` on pydantic-decorated classes so that mypy can see them.

## Enums

The preferred way to register an enum is with the decorator:

```python
from enum import Enum
import strawberry


@strawberry.enum
class IceCreamFlavour(Enum):
    VANILLA = "vanilla"
    STRAWBERRY = "strawberry"
```

If you need to expose an existing enum under a different name or alias, use
`Annotated` instead of assigning `strawberry.enum(IceCreamFlavour)` to a
variable — mypy treats the latter as a value, not a type, so it cannot be used
in annotations.

```python
from typing import Annotated
import strawberry

MyIceCreamFlavour = Annotated[IceCreamFlavour, strawberry.enum(description="...")]
```

`MyIceCreamFlavour` is a proper type alias that mypy and Pyright accept in
annotations.

---

### Editors Vscode (`docs/editors/vscode.md`)

---
title: Visual studio code
---

# Visual studio code

Strawberry comes with support for both MyPy and Pylance, Microsoft's own
language server for Python.

This guide will explain how to configure Visual Studio Code and Pylance to work
with Strawberry.

## Install Pylance

The first thing we need to do is to install
[Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance),
this is the extension that enables type checking and intellisense for Visual
Studio Code.

Once the extension is installed, we need to configure it to enable type
checking. To do so we need to change or add the following two settings:

```json
{
  "python.languageServer": "Pylance",
  "python.analysis.typeCheckingMode": "basic"
}
```

The first settings tells the editor to use Pylance as the language server. The
second setting tells the editor to enable type checking by using the basic type
checking mode. At the moment strict mode is not supported.

Once you have configured the settings, you can restart VS Code and you should be
getting type checking errors in vscode.

---

### Errors  Template (`docs/errors/_template.md`)

---
title: Some Error
---

# Some Error Error

## Description

This error is thrown when ... for example the following code will throw this
error:

```python
import strawberry

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

---

### Errors Conflicting Arguments (`docs/errors/conflicting-arguments.md`)

---
title: Conflicting Arguments Error
---

# Conflicting Arguments Error

## Description

This error is thrown when you define a resolver with multiple arguments that
conflict with each other, like "self", "root", or any arguments annotated with
strawberry.Parent.

For example the following code will throw this error:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello(
        self, root, parent: strawberry.Parent[str]
    ) -> str:  #  <-- self, root, and parent all identify the same input
        return f"hello world"
```

---

### Errors Duplicated Type Name (`docs/errors/duplicated-type-name.md`)

---
title: Duplicated Type Name Error
---

# Duplicated Type Name Error

## Description

This error is thrown when you try to register two types with the same name in
the schema.

For example, the following code will throw this error:

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type(name="User")
class UserB:
    name: str


@strawberry.type
class Query:
    user: User
    user_b: UserB


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

## How to fix this error

To fix this error you need to make sure that all the types in your schema have
unique names. For example in our example above we can fix this error by changing
the `name` argument of the `UserB` type:

```python
import strawberry


@strawberry.type
class User:
    name: str


# Note: Strawberry will automatically use the name of the class
# if it is not provided, in this case we are passing the name
# to show how it works and how to fix the error
@strawberry.type(name="UserB")
class UserB:
    name: str


@strawberry.type
class Query:
    user: User
    user_b: UserB


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

---

### Errors Invalid Argument Type (`docs/errors/invalid-argument-type.md`)

---
title: Invalid Argument Type Error
---

# Invalid Argument Type Error

## Description

This error is thrown when an argument is of the wrong type, it usually happens
when passing **unions** or **interfaces** as an argument, for example the
following code will throw this error:

```python
import strawberry

from typing import Union, Annotated


@strawberry.type
class TypeA:
    id: strawberry.ID


ExampleUnion = Annotated[Union[TypeA], strawberry.union("ExampleUnion")]


@strawberry.type
class Query:
    @strawberry.field
    def example(self, data: Example) -> str:
        return "this is an example"


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

## Using union types as arguments

The latest [GraphQL specification](https://spec.graphql.org/October2021/)
doesn't allow using unions as arguments. There's currently an
[RFC for adding a `oneOf` directive](https://github.com/graphql/graphql-spec/pull/825)
that might work for your use case, but it's not yet implemented in the spec and
Strawberry

---

### Errors Invalid One Of Input Field (`docs/errors/invalid-one-of-input-field.md`)

---
title: Invalid OneOf Input Field Error
---

# Invalid OneOf Input Field Error

## Description

This error is raised when a field of a OneOf input type (`one_of=True`) is
required or has a default value. Clients set exactly one field of a OneOf input
type, so GraphQL requires all its fields to be nullable and without a default.
For example, both fields of this input have a default, so when a client sets
`email`, GraphQL fills in `null` for `name`, and the input gets two keys:

```python
import strawberry


@strawberry.input(one_of=True)
class SearchBy:
    name: str | None = None
    email: str | None = None
```

A required field, like `name: str`, would have to be set in every request, so
clients couldn't set another field instead.

## How to fix this error

Make the fields nullable and remove their defaults. Strawberry sets the fields
that the client didn't set to `None`:

```python
import strawberry


@strawberry.input(one_of=True)
class SearchBy:
    name: str | None
    email: str | None
```

---

### Errors Invalid Strawberry Field Annotation (`docs/errors/invalid-strawberry-field-annotation.md`)

---
title: Invalid Strawberry Field Annotation Error
---

# Invalid Strawberry Field Annotation Error

## Description

This error is raised when `strawberry.field()` is nested inside another type in
a class-field annotation. For example, this attempts to configure a list item,
which is not a GraphQL field:

```python
from typing import Annotated

import strawberry


@strawberry.type
class Query:
    names: list[Annotated[str, strawberry.field(description="A name")]]
```

Strawberry only uses `strawberry.field()` metadata from the outermost
`Annotated` type because that node represents the class field.

## How to fix this error

Move `strawberry.field()` to the outermost `Annotated` metadata for the field:

```python
from typing import Annotated

import strawberry


@strawberry.type
class Query:
    names: Annotated[list[str], strawberry.field(description="The names")]
```

---

### Errors Invalid Superclass Interface (`docs/errors/invalid-superclass-interface.md`)

---
title: Invalid Superclass Interface Error
---

# Invalid Superclass Interface Error

## Description

This error is thrown when you define a class that has the `strawberry.input`
decorator but also inherits from one or more classes with the
`strawberry.interface` decorator. The underlying reason for this is that in
GraphQL, input types cannot implement interfaces. For example, the following
code will throw this error:

```python
import strawberry


@strawberry.interface
class SomeInterface:
    some_field: str


@strawberry.input
class SomeInput(SomeInterface):
    another_field: int
```

---

### Errors Invalid Type For Union Merge (`docs/errors/invalid-type-for-union-merge.md`)

---
title: Invalid Type for Union Merge Error
---

# Invalid Type for Union Merge Error

## Description

This error is thrown when trying to extend an union with a type that's not
allowed in unions, for example the following code will throw this error:

```python
import strawberry

from typing import Union, Annotated


@strawberry.type
class Example:
    name: str


ExampleUnion = Annotated[Union[Example], strawberry.union("ExampleUnion")]


@strawberry.type
class Query:
    field: ExampleUnion | int


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

This happens because GraphQL doesn't support scalars as union members.

## How to fix this error

At the moment Strawberry doesn't have a proper way to merge unions and types,
but you can still create a union type that combines multiple types manually.
Since GraphQL doesn't allow scalars as union members, a workaround is to create
a wrapper type that contains the scalar value and use that instead. For example
the following code will create a union type between `Example` and `IntWrapper`
which is a wrapper on top of the `int` scalar:

```python
import strawberry

from typing import Union, Annotated


@strawberry.type
class Example:
    name: str


@strawberry.type
class IntWrapper:
    value: int


ExampleUnion = Annotated[Union[Example, IntWrapper], strawberry.union("ExampleUnion")]


@strawberry.type
class Query:
    field: ExampleUnion


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

---

### Errors Invalid Union Type (`docs/errors/invalid-union-type.md`)

---
title: Invalid Type for Union Error
---

# Invalid Type for Union Error

## Description

This error is thrown when trying to create an union with one or more type that's
are allowed in unions, for example the following code will throw this error:

```python
import strawberry

from typing import Union, Annotated


@strawberry.type
class Example:
    name: str


ExampleUnion = Annotated[Union[Example, int], strawberry.union("ExampleUnion")]


@strawberry.type
class Query:
    field: ExampleUnion


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

This happens because GraphQL doesn't support scalars as union members.

## How to fix this error

Since GraphQL doesn't allow scalars as union members, a workaround is to create
a wrapper type that contains the scalar value and use that instead. For example
the following code will create a union type between `Example` and `IntWrapper`
which is a wrapper on top of the `int` scalar:

```python
import strawberry

from typing import Union, Annotated


@strawberry.type
class Example:
    name: str


@strawberry.type
class IntWrapper:
    value: int


ExampleUnion = Annotated[Union[Example, IntWrapper], strawberry.union("ExampleUnion")]


@strawberry.type
class Query:
    field: ExampleUnion


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

---

### Errors Missing Arguments Annotations (`docs/errors/missing-arguments-annotations.md`)

---
title: Missing arguments annotation Error
---

# Missing arguments annotation Error

## Description

This error is thrown when an argument is missing an annotation, for example the
following code will throw this error:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello(self, name) -> str:  #  <-- note name here is missing an annotation
        return f"hello {name}"


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

This happens because Strawberry needs to know the type of every argument to be
able to generate the correct GraphQL type.

## How to fix this error

You can fix this error by adding an annotation to the argument, for example, the
following code will fix this error:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello(self, name: str) -> str:
        return f"hello {name}"


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

---

### Errors Missing Field Annotation (`docs/errors/missing-field-annotation.md`)

---
title: Missing field annotation Error
---

# Missing field annotation Error

## Description

This error is thrown when a field on a class is missing an annotation, for
example the following code will throw this error:

```python
import strawberry


@strawberry.type
class Query:
    name: str
    age = strawberry.field(
        name="ageInYears"
    )  # note that here we don't have a type for this field


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

This happens because Strawberry needs to know the type of every field for a type
to be able to generate the correct GraphQL type.

## How to fix this error

You can fix this error by adding an annotation to the field, for example, the
following code will fix this error:

```python
import strawberry


@strawberry.type
class Query:
    name: str
    age: int = strawberry.field(name="ageInYears")


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

---

### Errors Missing Return Annotation (`docs/errors/missing-return-annotation.md`)

---
title: Missing return annotation Error
---

# Missing return annotation Error

## Description

This error is thrown when a resolver and it's corresponding field don't have a
return annotation, for example the following code will throw this error:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def example(self):
        return "this is an example"


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

This happens because Strawberry needs to know the return type of the resolver to
be able to generate the correct GraphQL type.

## How to fix this error

You can fix this error by adding a return annotation to the resolver, for
example, the following code will fix this error:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def example(self) -> str:
        return "this is an example"


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

---

### Errors Multiple Strawberry Fields (`docs/errors/multiple-strawberry-fields.md`)

---
title: Multiple Strawberry Fields Error
---

# Multiple Strawberry Fields Error

## Description

This error is raised when using multiple `strawberry.field()` annotations inside
an `Annotated` type. For example, the following code will raise this error:

```python
from typing import Annotated

import strawberry


@strawberry.type
class Query:
    name: Annotated[
        str,
        strawberry.field(description="First"),
        strawberry.field(description="Second"),
    ]


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

This happens because Strawberry only allows one `strawberry.field()` per field
when using the `Annotated` syntax. Having multiple would create ambiguity about
which field configuration to use.

## How to fix this error

You can fix this error by using only one `strawberry.field()` in your
`Annotated` type annotation. Combine all the options you need into a single
`strawberry.field()` call:

```python
from typing import Annotated

import strawberry


@strawberry.type
class Query:
    name: Annotated[
        str,
        strawberry.field(
            description="The name",
            deprecation_reason="Use fullName instead",
        ),
    ]


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

---

### Errors Node Id Annotation (`docs/errors/node-id-annotation.md`)

---
title: Node ID annotation error
---

# Node `ID` annotation errors

## Description

This error is thrown when a `relay.Node` implemented type can't resolve its `id`
field, due to it being missing or multiple annotated fields being found.

The following code will throw this error:

```python
import strawberry
from strawberry import relay


@strawberry.type
class Fruit(relay.Node):
    code: str
    name: str
```

This happens because `relay.Node` don't know which field should be used to
resolve to generate its `GlobalID` field.

The following would also throw this errors because multiple candidates were
found:

```python
import strawberry
from strawberry import relay


@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[str]
    name: relay.NodeID[str]
```

## How to fix this error

When inheriting from `relay.Node`, you should annotate exactly one `NodeID`
field in the type, like:

```python
import strawberry
from strawberry import relay


@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[str]
    name: str
```

---

### Errors Object Is Not An Enum (`docs/errors/object-is-not-an-enum.md`)

---
title: Object is not an Enum Error
---

# Object is not an Enum Error

## Description

This error is thrown when applying `@strawberry.enum` to a non-enum object, for
example the following code will throw this error:

```python
import strawberry


# note the lack of @strawberry.enum here:
class NotAnEnum:
    A = "A"


@strawberry.type
class Query:
    field: NotAnEnum


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

This happens because Strawberry expects all enums to be subclasses of `Enum`.

## How to fix this error

You can fix this error by making sure the class you're applying
`@strawberry.enum` to is a subclass of `Enum`. For example, the following code
will fix this error:

```python
import strawberry


@strawberry.enum
class NotAnEnum:
    A = "A"


@strawberry.type
class Query:
    field: NotAnEnum


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

---

### Errors Object Is Not Class (`docs/errors/object-is-not-class.md`)

---
title: Object is not an Class Error
---

# Object is not an Class Error

## Description

This error is thrown when applying `@strawberry.type/interface/input` to a
non-class object, for example the following code will throw this error:

```python
import strawberry


@strawberry.type
def a_function(): ...


@strawberry.type
class Query:
    field: a_function


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

This happens because Strawberry expects all enums to be subclasses of `Enum`.

## How to fix this error

You can fix this error by making sure the class you're applying
`@strawberry.type/interface/input` to is a class. For example, the following
code will fix this error:

```python
import strawberry


@strawberry.type
class AFunction:
    field: int


@strawberry.type
class Query:
    field: AFunction


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

---

### Errors Permission Fail Silently Requires Optional (`docs/errors/permission-fail-silently-requires-optional.md`)

---
title: Using silent permissions on optional fields
---

# Cannot use fail_silently on non-optional or non-list field

## Description

This error is thrown when a permission extension is configured to use silent
permissions on a field that is required and not a list:

```python
import strawberry
from strawberry.permission import PermissionExtension


@strawberry.type
class Query:
    @strawberry.field(
        extensions=[PermissionExtension([IsAuthorized()], fail_silently=True)]
    )
    def name(
        self,
    ) -> str:  # This is a required field, the schema type will be NonNull (String!)
        return "ABC"


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

This happens because fail_silently is suppsed to hide the field from a user
without an error in case of no permissions. However, non-nullable fields always
raise an error when they are set to null. The only exception to that is a list,
because an empty list can be returned.

## How to fix this error

You can fix this error by making this field an optional field. For example, the
following code will fix this error in the above example:

```python
import strawberry
from strawberry.permission import PermissionExtension


@strawberry.type
class Query:
    @strawberry.field(
        extensions=[PermissionExtension([IsAuthorized()], fail_silently=True)]
    )
    def name(self) -> str | None:  # This is now a nullable field
        return "ABC"


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

Alternatively, not using `fail_silently` might be a good design choice as well.

---

### Errors Private Strawberry Field (`docs/errors/private-strawberry-field.md`)

---
title: Private Strawberry Field Error
---

# Private Strawberry Field Error

## Description

This error is thrown when using both `strawberry.Private[Type]` and
`strawberry.field` on the same field, for example the following code will throw
this error:

```python
import strawberry


@strawberry.type
class Query:
    name: str
    age: strawberry.Private[int] = strawberry.field(name="ageInYears")


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

This happens because a `strawberry.Private` field is not going to be exposed in
the GraphQL schema, so using `strawberry.field` on that field won't be useful,
since it is meant to be used to change information about a field that is exposed
in the GraphQL schema.

<Note>
  This makes sense, but now we don't have a way to do something like:
  strawberry.Private[list[str]] = strawberry.field(default_factory=list)
  (workaround is to use dataclasses.field, explained below)
</Note>

## How to fix this error

You can fix this error by either removing the `strawberry.Private` annotation or
by removing the `strawberry.field` usage. If you need to specify a default value
using `default_factory` you can use `dataclasses.field` instead of
`strawberry.field`. For example:

```python
import strawberry
import dataclasses


@strawberry.type
class Query:
    name: str
    tags: strawberry.Private[str] = dataclasses.field(default_factory=list)


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

---

### Errors Relay Wrong Annotation (`docs/errors/relay-wrong-annotation.md`)

---
title: Relay wrong annotation Error
---

# Relay wrong annotation error

## Description

This error is thrown when a field on a relay connection has a wrong type
annotation. For example, the following code will throw this error:

```python
from typing import List

import strawberry
from strawberry import relay


@strawberry.type
class MyType(relay.Node): ...


@strawberry.type
class Query:
    # The annotation is not a subclass of relay.Connection
    my_type_conn: List[MyType] = relay.connection()

    # Missing the Connection class annotation
    @relay.connection
    def my_type_conn_with_resolver(self) -> List[MyType]: ...

    # The connection class is not a subclass of relay.Connection
    @relay.connection(List[MyType])
    def my_type_conn_with_resolver2(self) -> List[MyType]: ...
```

## How to fix this error

You can fix this error by properly annotating your attribute or resolver with
`relay.Connection` type subclass.

For example:

```python
from typing import List

import strawberry
from strawberry import relay


@strawberry.type
class MyType(relay.Node): ...


def get_my_type_list() -> List[MyType]: ...


@strawberry.type
class Query:
    my_type_conn: relay.Connection[MyType] = relay.connection(
        resolver=get_my_type_list,
    )

    # Missing the Connection class annotation
    @relay.connection(relay.Connection[MyType])
    def my_type_conn_with_resolver(self) -> List[MyType]: ...

    # The connection class is not a subclass of relay.Connection
    @relay.connection(relay.Connection[MyType])
    def my_type_conn_with_resolver2(self) -> List[MyType]: ...
```

---

### Errors Relay Wrong Resolver Annotation (`docs/errors/relay-wrong-resolver-annotation.md`)

---
title: Relay wrong resolver annotation Error
---

# Relay wrong resolver annotation error

## Description

This error is thrown when a field on a relay connection was defined with a
resolver that returns something that is not compatible with pagination.

For example, the following code would throw this error:

```python
from typing import Any

import strawberry
from strawberry import relay


@strawberry.type
class MyType(relay.Node): ...


@strawberry.type
class Query:
    @relay.connection(relay.Connection[MyType])
    def some_connection_returning_mytype(self) -> MyType: ...

    @relay.connection(relay.Connection[MyType])
    def some_connection_returning_any(self) -> Any: ...
```

This happens because the connection resolver needs to return something that can
be paginated, usually an iterable/generator of the connection type itself.

## How to fix this error

You can fix this error by annotating the resolver with one of the following
supported types:

- `List[<NodeType>]`
- `Iterator[<NodeType>]`
- `Iterable[<NodeType>]`
- `AsyncIterator[<NodeType>]`
- `AsyncIterable[<NodeType>]`
- `Generator[<NodeType>, Any, Any]`
- `AsyncGenerator[<NodeType>, Any]`

For example:

```python
from typing import Any

import strawberry
from strawberry import relay


@strawberry.type
class MyType(relay.Node): ...


@strawberry.type
class Query:
    @relay.connection(relay.Connection[MyType])
    def some_connection(self) -> Iterable[MyType]: ...
```

<Note>
  Note that if you are returning a type different than the connection type, you
  will need to subclass the connection type and override its `resolve_node`
  method to convert it to the correct type, as explained in the [relay
  guide](../guides/relay).
</Note>

---

### Errors Resolver Field On Input (`docs/errors/resolver-field-on-input.md`)

---
title: Resolver Field On Input Error
---

# Resolver Field On Input Error

## Description

This error is thrown when a field of an input type has a resolver, for example
the following code will throw this error:

```python
import strawberry


@strawberry.input
class UserInput:
    name: str

    @strawberry.field
    def upper_name(self) -> str:
        return self.name.upper()
```

This happens because input types only hold the values sent by the client, so
their fields can't be resolved: the resolver would never run, and every request
using the input would fail, as the field can't be passed to the input type.

The same applies to fields inherited from an output type, like in
`class UserInput(User)`, when `User` has fields with resolvers.

## How to fix this error

You can fix this error by removing the resolver, or by moving the field to an
output type:

```python
import strawberry


@strawberry.input
class UserInput:
    name: str


@strawberry.type
class User:
    name: str

    @strawberry.field
    def upper_name(self) -> str:
        return self.name.upper()
```

When the field is inherited, move the fields to share to a base type without
resolvers, and inherit from it in both types:

```python
import strawberry


@strawberry.type
class UserBase:
    name: str


@strawberry.type
class User(UserBase):
    @strawberry.field
    def upper_name(self) -> str:
        return self.name.upper()


@strawberry.input
class UserInput(UserBase):
    pass
```

---

### Errors Scalar Already Registered (`docs/errors/scalar-already-registered.md`)

---
title: Scalar already registered Error
---

# Scalar already registered Error

## Description

This error is thrown when trying to use a scalar that is already registered.
This usually happens when using the same name for different scalars, for example
the following code will throw this error:

```python
import strawberry

MyCustomScalar = strawberry.scalar(
    str,
    name="MyCustomScalar",
)

MyCustomScalar2 = strawberry.scalar(
    int,
    name="MyCustomScalar",
)


@strawberry.type
class Query:
    scalar_1: MyCustomScalar
    scalar_2: MyCustomScalar2


strawberry.Schema(Query)
```

This happens because different types in Strawberry (and GraphQL) cannot have the
same name.

<Note>
  This error might happen also when trying to defined a scalar with the same
  name as a type.
</Note>

## How to fix this error

You can fix this error by either reusing the existing scalar, or by changing the
name of one of them, for example in this code we renamed the second scalar:

```python
import strawberry

MyCustomScalar = strawberry.scalar(
    str,
    name="MyCustomScalar",
)

MyCustomScalar2 = strawberry.scalar(
    int,
    name="MyCustomScalar2",
)


@strawberry.type
class Query:
    scalar_1: MyCustomScalar
    scalar_2: MyCustomScalar2


strawberry.Schema(Query)
```

---

### Errors Undecorated Subclass (`docs/errors/undecorated-subclass.md`)

---
title: Undecorated Subclass Error
---

# Undecorated Subclass Error

## Description

This error is thrown when a subclass of a Strawberry type, input type or
interface is used in the schema without being decorated itself, for example the
following code will throw this error:

```python
import strawberry


@strawberry.type
class Animal:
    name: str


class Dog(Animal):
    breed: str


@strawberry.type
class Query:
    dog: Dog


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

This happens because `Dog` inherits the Strawberry definition of `Animal`, so it
would be published as `Animal`, without the `breed` field. For input types, the
schema would only accept the fields of the parent input type, and the fields
declared on the subclass would be missing from the instances passed to your
resolvers.

The error is raised for every type used in the schema: field and argument
annotations (including in lists, optionals and unions), lazy types, the types
passed to `strawberry.Schema(types=[...])` and the query, mutation and
subscription types.

## How to fix this error

You can fix this error by decorating the subclass, with `@strawberry.type` for
types and interfaces, or with `@strawberry.input` for input types:

```python
import strawberry


@strawberry.type
class Animal:
    name: str


@strawberry.type
class Dog(Animal):
    breed: str


@strawberry.type
class Query:
    dog: Dog


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

If you meant to publish the parent type, use it in the annotation instead.
Resolvers can still return instances of undecorated subclasses, as they are
instances of the parent type:

```python
import strawberry


@strawberry.type
class Animal:
    name: str


class Dog(Animal):
    def bark(self) -> str:
        return "Woof!"


@strawberry.type
class Query:
    @strawberry.field
    def animal(self) -> Animal:
        return Dog(name="Rex")


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

---

### Errors Unresolved Field Type (`docs/errors/unresolved-field-type.md`)

---
title: Unresolved Field Type Error
---

# Unresolved Field Type Error

## Description

This error is thrown when Strawberry is unable to resolve a field type. This
happens when the type of a field is not accessible in the current scope. For
example the following code will throw this error:

```python
import strawberry


@strawberry.type
class Query:
    user: "User"


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

<Note>

Note that we are using the forward reference syntax to define the type of the
field. This is because the `User` type is not yet defined when the `Query` type
is defined.

This would also happen when using `from __future__ import annotations`.

</Note>

To fix this error you need to import the type that you are using in the field,
for example:

```python
import strawberry
from .user import User


@strawberry.type
class Query:
    user: "User"


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

Unfortunately, this won't work in cases where there's a circular dependency
between types. In this case, you can use `strawberry.LazyType`.

---

### Errors Unresolved Strawberry Field (`docs/errors/unresolved-strawberry-field.md`)

---
title: Unresolved Strawberry Field Error
---

# Unresolved Strawberry Field Error

## Description

This error is raised when Strawberry can't read the `strawberry.field()` options
in a field's annotation when the type is created:

- on Python 3.11 to 3.13, when the annotation uses a type that isn't defined
  yet;
- on every Python version, when the options themselves use names that aren't
  defined yet, like a permission class defined after the type.

For example, a type defined further down the module, in a module with
`from __future__ import annotations`:

```python
from __future__ import annotations

from typing import Annotated

import strawberry


@strawberry.type
class User:
    account: Annotated[Account, strawberry.field(permission_classes=[IsAdmin])]


@strawberry.type
class Account:
    iban: str
```

Strawberry reads the `strawberry.field()` options when the type is created, but
before Python 3.14 it can't evaluate an annotation that uses names that aren't
defined yet. The type itself is resolved later, when the schema is built, so
instead of silently ignoring options like the permissions above, Strawberry
raises this error.

The same applies to a shared field, like `Annotated[Account, ADMIN_ONLY_FIELD]`,
and to an `Annotated` alias with `strawberry.field()`, like
`AdminOnly[Account]`.

## How to fix this error

Pass the options as the field's default instead of in `Annotated`. This works
for any type, including types that reference themselves:

```python
from __future__ import annotations

import strawberry


@strawberry.type
class User:
    account: Account = strawberry.field(permission_classes=[IsAdmin])


@strawberry.type
class Account:
    iban: str
```

Or define the types the annotation uses before the type that uses them:

```python
from __future__ import annotations

from typing import Annotated

import strawberry


@strawberry.type
class Account:
    iban: str


@strawberry.type
class User:
    account: Annotated[Account, strawberry.field(permission_classes=[IsAdmin])]
```

Or use `strawberry.lazy()` for the type, for example for types only imported
under `TYPE_CHECKING`. It works together with `strawberry.field()`:

```python
from __future__ import annotations

from typing import TYPE_CHECKING, Annotated

import strawberry

if TYPE_CHECKING:
    from .accounts import Account


@strawberry.type
class User:
    account: Annotated[
        Account,
        strawberry.lazy(".accounts"),
        strawberry.field(permission_classes=[IsAdmin]),
    ]
```

Python 3.14 and newer read the options of these annotations without any change.

The names used by the options themselves, like a permission class, a directive
or a default value, have to be defined before the type on every Python version,
as the options are evaluated when the type is created:

```python
from __future__ import annotations

from typing import Annotated

import strawberry


class IsAdmin(BasePermission): ...  # defined before `User`


@strawberry.type
class User:
    account: Annotated[Account, strawberry.field(permission_classes=[IsAdmin])]
```

An `Annotated` alias with `strawberry.field()`, like `AdminOnly[Account]`, has
to be defined before the types that use it, on every Python version.

---

### Errors Unsupported Type (`docs/errors/unsupported-type.md`)

---
title: Unsupported Type Error
---

# Unsupported Type Error

## Description

This error is thrown when trying to convert arguments with a type that
Strawberry doesn't know about. It shouldn't happen with normal usage of
Strawberry.

---

### Extensions  Template (`docs/extensions/_template.md`)

---
title: Extension Name
summary: A summary of the extension.
tags: comma,separated,list,of,tags
---

# `ExtensionName`

This extension does ...

## Usage example:

```python
import strawberry
from strawberry.extensions import ExtensionName


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ExtensionName(),
    ],
)
```

## API reference:

```python
class ExtensionName(an_argument=None): ...
```

#### `an_argument: Optional[str] = None`

Description of the argument.

## More examples:

<details>
  <summary>Using `an_argument`</summary>

```python
import strawberry
from strawberry.extensions import ValidationCache

schema = strawberry.Schema(
    Query,
    extensions=[
        ExtensionName(an_argument="something"),
    ],
)
```

</details>

---

### Extensions Add Validation Rules (`docs/extensions/add-validation-rules.md`)

---
title: Add Validation Rules
summary: Add GraphQL validation rules.
tags: validation,security
---

# `AddValidationRules`

This extension allows you add custom validation rules.

See
[graphql.validation.rules.custom](https://github.com/graphql-python/graphql-core/tree/main/src/graphql/validation/rules/custom)
for some custom rules that can be added from GraphQl-core.

## Usage example:

```python
import strawberry
from strawberry.extensions import AddValidationRules
from graphql import ValidationRule


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


class MyCustomRule(ValidationRule): ...


schema = strawberry.Schema(
    Query,
    extensions=[
        AddValidationRules(MyCustomRule),
    ],
)
```

## API reference:

```python
class AddValidationRules(validation_rules): ...
```

#### `validation_rules: List[Type[ASTValidationRule]]`

List of GraphQL validation rules.

## More examples:

<details>
  <summary>Adding a custom rule</summary>

```python
import strawberry
from strawberry.extensions import AddValidationRules
from graphql import ValidationRule


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


class CustomRule(ValidationRule):
    def enter_field(self, node, *args) -> None:
        if node.name.value == "example":
            self.report_error(GraphQLError("Can't query field 'example'"))


schema = strawberry.Schema(
    Query,
    extensions=[
        AddValidationRules([CustomRule]),
    ],
)

result = schema.execute_sync("{ example }")

assert str(result.errors[0]) == "Can't query field 'example'"
```

</details>

<details>
  <summary>Adding the `NoDeprecatedCustomRule` from GraphQL-core</summary>

```python
import strawberry
from strawberry.extensions import AddValidationRules
from graphql.validation import NoDeprecatedCustomRule


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        AddValidationRules([NoDeprecatedCustomRule]),
    ],
)
```

</details>

<details>
  <summary>Adding the `NoSchemaIntrospectionCustomRule` from GraphQL-core</summary>

```python
import strawberry
from strawberry.extensions import AddValidationRules
from graphql.validation import NoSchemaIntrospectionCustomRule


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        AddValidationRules([NoSchemaIntrospectionCustomRule]),
    ],
)
```

</details>

---

### Extensions Apollo Federation Tracing (`docs/extensions/apollo-federation-tracing.md`)

---
title: Apollo Federation Tracing
summary: Add Apollo Federation inline tracing (FTV1) to your GraphQL server.
tags: tracing,federation
---

# `ApolloFederationTracingExtension`

This extension adds support for
[Apollo Federation inline tracing (FTV1)](https://www.apollographql.com/docs/federation/).
When a request includes the `apollo-federation-include-trace: ftv1` header, the
extension records per-resolver timing and includes the trace in the response as
a base64-encoded protobuf under `extensions.ftv1`.

<Warning>

Any client can send the `apollo-federation-include-trace: ftv1` header unless
you restrict it. Tracing payloads expose resolver timing details, so make sure
only a trusted Apollo Gateway (or other internal traffic) can request traces —
for example by enforcing authentication, network policy, or stripping the header
from public requests at the edge.

</Warning>

<Note>

Make sure you have `protobuf` installed before using this extension.

```shell
pip install 'strawberry-graphql[apollo-federation]'
```

</Note>

## Usage example:

```python
import strawberry
from strawberry.extensions.tracing import ApolloFederationTracingExtension


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ApolloFederationTracingExtension,
    ],
)
```

<Note>

If you are not running in an Async context then you'll need to use the sync
version:

```python
import strawberry
from strawberry.extensions.tracing import ApolloFederationTracingExtensionSync


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ApolloFederationTracingExtensionSync,
    ],
)
```

</Note>

## API reference:

_No arguments_

---

### Extensions Apollo Tracing (`docs/extensions/apollo-tracing.md`)

---
title: Apollo Tracing
summary: Add Apollo tracing to your GraphQL server.
tags: tracing
---

# `ApolloTracingExtension`

This extension adds
[tracing information](https://github.com/apollographql/apollo-tracing) to your
response for [Apollo Engine](https://www.apollographql.com/platform/).

## Usage example:

```python
import strawberry
from strawberry.extensions.tracing import ApolloTracingExtension


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ApolloTracingExtension,
    ],
)
```

<Note>

If you are not running in an Async context then you'll need to use the sync
version:

```python
import strawberry
from strawberry.extensions.tracing import ApolloTracingExtensionSync


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ApolloTracingExtensionSync,
    ],
)
```

</Note>

## API reference:

_No arguments_

---

### Extensions Datadog (`docs/extensions/datadog.md`)

---
title: Datadog
summary: Add Datadog tracing to your GraphQL server.
tags: tracing
---

# `DatadogExtension`

This extension adds support for tracing with Datadog.

<Note>

Make sure you have `ddtrace` installed before using this extension.

```shell
pip install ddtrace
```

</Note>

## Usage example:

```python
import strawberry
from strawberry.extensions.tracing import DatadogTracingExtension


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        DatadogTracingExtension,
    ],
)
```

<Note>

If you are not running in an Async context then you'll need to use the sync
version:

```python
import strawberry
from strawberry.extensions.tracing import DatadogTracingExtensionSync


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        DatadogTracingExtensionSync,
    ],
)
```

</Note>

## API reference:

_No arguments_

## Extending the extension

### Overriding the `create_span` method

You can customize any of the spans or add tags to them by overriding the
`create_span` method.

Example:

```python
from ddtrace import Span

from strawberry.extensions import LifecycleStep
from strawberry.extensions.tracing import DatadogTracingExtension


class DataDogExtension(DatadogTracingExtension):
    def create_span(
        self,
        lifecycle_step: LifecycleStep,
        name: str,
        **kwargs,
    ) -> Span:
        span = super().create_span(lifecycle_step, name, **kwargs)
        if lifecycle_step == LifecycleStep.OPERATION:
            span.set_tag("graphql.query", self.execution_context.query)
        return span
```

---

### Extensions Disable Introspection (`docs/extensions/disable-introspection.md`)

---
title: Disable Introspection
summary: Disable standard GraphQL introspection queries.
tags: security,validation
---

# `DisableIntrospection`

The `DisableIntrospection` extension disables standard GraphQL introspection
queries for the schema. It blocks fields such as `__schema` and `__type`.

This can be useful to prevent clients from discovering unreleased or internal
features of the API through GraphQL introspection.

<Warning>

`DisableIntrospection` does not block non-introspection fields that may expose
schema information. For example, Apollo Federation schemas expose `_service` and
its `sdl` field so gateways and routers can compose federated services. If you
use `strawberry.federation.Schema`, protect federated endpoints from untrusted
clients with your own authentication, authorization, or network controls.

</Warning>

## Usage example:

```python
import strawberry
from strawberry.extensions import DisableIntrospection


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        DisableIntrospection(),
    ],
)
```

## API reference:

_No arguments_

## Example query:

Running any query including the introspection field `__schema` will result in an
error. Consider the following query, for example:

```graphql
query {
  __schema {
    __typename
  }
}
```

Running it against the schema with the `DisableIntrospection` extension enabled
will result in an error response indicating that introspection has been
disabled:

```json
{
  "data": null,
  "errors": [
    {
      "message": "GraphQL introspection has been disabled, but the requested query contained the field '__schema'.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}
```

---

### Extensions Disable Validation (`docs/extensions/disable-validation.md`)

---
title: Disable Validation
summary: Disable all query validation.
tags: performance,validation
---

# `DisableValidation`

This extensions disables all query validation. This can be useful to improve
performance in some specific cases, for example when dealing with internal APIs
where queries can be trusted.

<Warning>

Only do this if you know what you are doing! Disabling validation breaks the
safety of having typed schema. If you are trying to improve performance you
might want to consider using the [ValidationCache](./validation-cache) instead.

</Warning>

## Usage example:

```python
import strawberry
from strawberry.extensions import DisableValidation


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        DisableValidation(),
    ],
)
```

## API reference:

_No arguments_

---

### Extensions Input Mutation (`docs/extensions/input-mutation.md`)

---
title: Input Mutation Extension
summary: Automatically create Input types for mutations
tags: QoL
---

# `InputMutationExtension`

The pattern of defining a mutation that receives a single
[input type](../types/input-types.md) argument called `input` is a common
practice in GraphQL. It helps to keep the mutation signatures clean and makes it
easier to manage complex mutations with multiple arguments.

The `InputMutationExtension` is a Strawberry field extension that allows you to
define a mutation with multiple arguments without having to manually create an
input type for it. Instead, it generates an input type based on the arguments of
the mutation resolver.

## Usage example:

```python
import strawberry
from strawberry.field_extensions import InputMutationExtension


@strawberry.type
class User:
    username: str


@strawberry.type
class Query:
    hello: str


@strawberry.type
class Mutation:
    @strawberry.mutation(extensions=[InputMutationExtension()])
    def register_user(
        self,
        username: str,
        password: str,
    ) -> User:
        user = User(username=username)
        # maybe persist the user in a database
        return user


schema = strawberry.Schema(query=Query, mutation=Mutation)
```

The Strawberry schema above and the usage of the `InputMutationExtension` will
result in the following GraphQL schema:

```graphql
type User {
  username: String!
}

input RegisterUserInput {
  username: String!
  password: String!
}

type Mutation {
  registerUser(input: RegisterUserInput!): User!
}

type Query {
  hello: String!
}
```

## API reference:

_No arguments_

---

### Extensions Mask Errors (`docs/extensions/mask-errors.md`)

---
title: Mask Errors
summary: Hide error messages from the client.
tags: security
---

# `MaskErrors`

This extension hides error messages from the client to prevent exposing
sensitive details. By default it masks all errors raised in any field resolver.

## Usage example:

```python
import strawberry
from strawberry.extensions import MaskErrors


@strawberry.type
class Query:
    @strawberry.field
    def hidden_error(self) -> str:
        raise KeyError("This error will not be visible")


schema = strawberry.Schema(
    Query,
    extensions=[
        MaskErrors(),
    ],
)
```

## API reference:

```python
class MaskErrors(
    should_mask_error=default_should_mask_error, error_message="Unexpected error."
): ...
```

#### `should_mask_error: Callable[[GraphQLError], bool] = default_should_mask_error`

Predicate function to check if a GraphQLError should be masked or not. Use the
`original_error` attribute to access the original error that was raised in the
resolver.

<Note>

The `default_should_mask_error` function always returns `True`.

</Note>

#### `error_message: str = "Unexpected error."`

The error message to display to the client when there is an error.

## More examples:

<details>
  <summary>Hide some exceptions</summary>

```python
import strawberry
from strawberry.extensions import MaskErrors
from graphql.error import GraphQLError


class VisibleError(Exception):
    pass


@strawberry.type
class Query:
    @strawberry.field
    def visible_error(self) -> str:
        raise VisibleError("This error will be visible")


def should_mask_error(error: GraphQLError) -> bool:
    original_error = error.original_error
    if original_error and isinstance(original_error, VisibleError):
        return False

    return True


schema = strawberry.Schema(
    Query,
    extensions=[
        MaskErrors(should_mask_error=should_mask_error),
    ],
)
```

</details>

<details>
  <summary>Change error message</summary>

```python
import strawberry
from strawberry.extensions import MaskErrors


@strawberry.type
class Query:
    @strawberry.field
    def hidden_error(self) -> str:
        raise KeyError("This error will not be visible")


schema = strawberry.Schema(
    Query,
    extensions=[
        MaskErrors(error_message="Oh no! An error occured. Very sorry about that."),
    ],
)
```

</details>

---

### Extensions Max Aliases Limiter (`docs/extensions/max-aliases-limiter.md`)

---
title: Max Aliases Limiter
summary:
  Add a validator to limit the maximum number of aliases in a GraphQL document.
tags: security
---

# `MaxAliasesLimiter`

This extension adds a validator to limit the maximum number of aliases in a
GraphQL document.

## Usage example:

```python
import strawberry
from strawberry.extensions import MaxAliasesLimiter


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        MaxAliasesLimiter(max_alias_count=15),
    ],
)
```

## API reference:

```python
class MaxAliasesLimiter(max_alias_count): ...
```

#### `max_alias_count: int`

The maximum allowed number of aliases in a GraphQL document.

---

### Extensions Max Tokens Limiter (`docs/extensions/max-tokens-limiter.md`)

---
title: Max Tokens Limiter
summary:
  Add a validator to limit the maximum number of tokens in a GraphQL document.
tags: security
---

# `MaxTokensLimiter`

This extension adds a validator to limit the maximum number of tokens in a
GraphQL document sent to the server.

## Usage example:

```python
import strawberry
from strawberry.extensions import MaxTokensLimiter


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        MaxTokensLimiter(max_token_count=1000),
    ],
)
```

With the above configuration, if a client sends a query with more than 1000
tokens, the server will respond with an error message.

## API reference:

```python
class MaxTokensLimiter(max_token_count): ...
```

#### `max_token_count: int`

The maximum allowed number of tokens in a GraphQL document.

The following things are counted as tokens:

- various brackets: "{", "}", "(", ")"
- colon :
- words

Not counted:

- quotes

---

### Extensions Opentelemetry (`docs/extensions/opentelemetry.md`)

---
title: Open Telemetry
summary: Add Open Telemetry tracing to your GraphQL server.
tags: tracing
---

# `OpenTelemetryExtension`

This extension adds tracing information that is compatible with
[Open Telemetry](https://opentelemetry.io/).

<Note>

This extension requires additional requirements:

```shell
pip install 'strawberry-graphql[opentelemetry]'
```

</Note>

## Usage example:

```python
import strawberry
from strawberry.extensions.tracing import OpenTelemetryExtension


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        OpenTelemetryExtension,
    ],
)
```

<Note>

If you are not running in an Async context then you'll need to use the sync
version:

```python
import strawberry
from strawberry.extensions.tracing import OpenTelemetryExtensionSync


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        OpenTelemetryExtensionSync,
    ],
)
```

</Note>

## API reference:

```python
class OpenTelemetryExtension(arg_filter=None): ...
```

#### `arg_filter: Optional[ArgFilter]`

A function to filter certain field arguments from being included in the tracing
data.

```python
ArgFilter = Callable[[Dict[str, Any], GraphQLResolveInfo], Dict[str, Any]]
```

## More examples:

<details>
  <summary>Using `arg_filter`</summary>

```python
import strawberry
from strawberry.extensions.tracing import OpenTelemetryExtensionSync


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


def arg_filter(kwargs, info):
    filtered_kwargs = {}
    for name, value in kwargs.items():
        # Never include any arguments called "password"
        if name == "password":
            continue
        filtered_kwargs[name] = value

    return filtered_kwargs


schema = strawberry.Schema(
    Query,
    extensions=[
        OpenTelemetryExtensionSync(
            arg_filter=arg_filter,
        ),
    ],
)
```

</details>

<details>
  <summary>Using `tracer_provider`</summary>

```python
import strawberry
from opentelemetry.trace import TracerProvider
from strawberry.extensions.tracing import OpenTelemetryExtension


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


class MyTracerProvider(TracerProvider):
    def get_tracer(self, name, version=None, schema_url=None):
        return super().get_tracer(name, version, schema_url)


schema = strawberry.Schema(
    Query,
    extensions=[
        OpenTelemetryExtension(
            tracer_provider=MyTracerProvider(),
        ),
    ],
)
```

</details>

---

### Extensions Parser Cache (`docs/extensions/parser-cache.md`)

---
title: Parser Cache
summary: Add in memory caching to the parsing step of query execution.
tags: performance,caching,parsing
---

# `ParserCache`

This extension adds LRU caching to the parsing step of query execution to
improve performance by caching the parsed result in memory.

## Usage example:

```python
import strawberry
from strawberry.extensions import ParserCache


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ParserCache(),
    ],
)
```

## API reference:

```python
class ParserCache(maxsize=128): ...
```

#### `maxsize: Optional[int] = 128`

Set the maxsize of the cache. By default the cache is bounded to 128 entries,
with the least recently used entries evicted first. Pass an explicit
`maxsize=None` to let the cache grow without bound; only do this when the set of
distinct query texts reaching the server is trusted and bounded, as an unbounded
cache lets clients grow the server's memory indefinitely by sending unique query
texts.

More info: https://docs.python.org/3/library/functools.html#functools.lru_cache

## More examples:

<details>
  <summary>Using maxsize</summary>

```python
import strawberry
from strawberry.extensions import ParserCache


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ParserCache(maxsize=100),
    ],
)
```

</details>

---

### Extensions Pydantic Error Extension (`docs/extensions/pydantic_error_extension.md`)

---
title: Pydantic Error Extension
summary:
  Formats Pydantic validation errors into structured GraphQL error extensions.
tags: pydantic,validation,errors,graphql,extensions
---

# `PydanticErrorExtension`

This extension detects Pydantic validation errors during GraphQL execution and
formats them into structured `validation_errors` under the `extensions` field of
GraphQL errors.

## Usage example:

```python
import strawberry
from strawberry.extensions import PydanticErrorExtension


@strawberry.type
class Mutation:
    @strawberry.mutation
    def create_user(self, email: str) -> str:
        return email


schema = strawberry.Schema(
    mutation=Mutation,
    extensions=[
        PydanticErrorExtension(),
    ],
)
```

## API reference:

```python
class PydanticErrorExtension: ...
```

This extension does not require any arguments.

## More examples:

<details>
  <summary>Example validation error output</summary>

```json
{
  "errors": [
    {
      "message": "Validation error",
      "extensions": {
        "validation_errors": [
          {
            "field": "email",
            "message": "value is not a valid email"
          }
        ]
      }
    }
  ]
}
```

</details>

---

### Extensions Pyinstrument (`docs/extensions/pyinstrument.md`)

---
title: PyInstrument
summary: Easily Instrument your Schema
tags: instrumentation,profiling
---

# `PyInstrument`

This extension allows you to instrument your schema and inspect the call stack.

## Usage example:

```python
import strawberry
from strawberry.extensions import pyinstrument


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        pyinstrument.PyInstrument(report_path="pyinstrument.html"),
    ],
)
```

## API reference:

```python
class PyInstrument(report_Path=Path("pyinstrument.html")): ...
```

#### `report_path: Path = Path("pyinstrument.html")`

Path to write the HTML PyInstrument report

---

### Extensions Query Depth Limiter (`docs/extensions/query-depth-limiter.md`)

---
title: Query Depth Limiter
summary: Add a validator to limit the query depth of GraphQL operations.
tags: security
---

# `QueryDepthLimiter`

This extension adds a validator to limit the query depth of GraphQL operations.

## Usage example:

```python
import strawberry
from strawberry.extensions import QueryDepthLimiter


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        QueryDepthLimiter(max_depth=10),
    ],
)
```

## API reference:

```python
class QueryDepthLimiter(max_depth, callback=None, should_ignore=None): ...
```

#### `max_depth: int`

The maximum allowed depth for any operation in a GraphQL document.

#### `callback: Optional[Callable[[Dict[str, int]], None]`

Called each time validation runs. Receives a dictionary which is a map of the
depths for each operation.

#### `should_ignore: Optional[Callable[[IgnoreContext], bool]]`

Called at each field to determine whether the field should be ignored or not.
Must be implemented by the user and returns `True` if the field should be
ignored and `False` otherwise.

The `IgnoreContext` class has the following attributes:

- `field_name` of type `str`: the name of the field to be compared against
- `field_args` of type
  `strawberry.extensions.query_depth_limiter.FieldArgumentsType`: the arguments
  of the field to be compared against
- `query` of type `graphql.language.Node`: the query string
- `context` of type `graphql.validation.ValidationContext`: the context passed
  to the query

This argument is injected, regardless of name, by the `QueryDepthLimiter` class
and should not be passed by the user.

Instead, the user should write business logic to determine whether a field
should be ignored or not by the attributes of the `IgnoreContext` class.

## Example with field_name:

```python
import strawberry
from strawberry.extensions import QueryDepthLimiter, IgnoreContext


@strawberry.type
class Book:
    title: str
    author: "User"


@strawberry.type
class User:
    favourite_books: list[Book]
    published_books: list[Book]


@strawberry.type
class Query:
    @strawberry.field
    def book(self) -> Book:
        return Book(
            title="The Hitchhiker's Guide to the Strawberry Fields",
            author=User(favourite_books=[], published_books=[]),
        )

    @strawberry.field
    def user(self) -> User:
        return User(favourite_books=[], published_books=[])


def should_ignore(ignore: IgnoreContext):
    return ignore.field_name == "user"


schema = strawberry.Schema(
    Query,
    extensions=[
        QueryDepthLimiter(max_depth=2, should_ignore=should_ignore),
    ],
)

# This query fails
schema.execute("""
    query TooDeep {
        book {
            author {
                publishedBooks {
                    title
                }
            }
        }
    }
    """)

# This query succeeds because the `user` field is ignored
schema.execute("""
    query NotTooDeep {
        user {
            favouriteBooks {
                author {
                    publishedBooks {
                        title
                    }
                }
            }
        }
    }
    """)
```

## Example with field_args:

```python
import strawberry
from strawberry.extensions import QueryDepthLimiter, IgnoreContext


@strawberry.type
class Book:
    title: str
    author: "User"


@strawberry.type
class User:
    name: str | None
    favourite_books: list[Book]
    published_books: list[Book]


@strawberry.type
class Query:
    @strawberry.field
    def book(self) -> Book:
        return Book(
            title="The Hitchhiker's Guide to the Strawberry Fields",
            author=User(favourite_books=[], published_books=[]),
        )

    @strawberry.field
    def user(self, name: str | None = None) -> User:
        return User(name=name, favourite_books=[], published_books=[])


def should_ignore(ignore: IgnoreContext):
    return ignore.field_args.get("name") == "matt"


schema = strawberry.Schema(
    Query,
    extensions=[
        QueryDepthLimiter(max_depth=2, should_ignore=should_ignore),
    ],
)

# This query fails
schema.execute("""
    query TooDeep {
        book {
            author {
                publishedBooks {
                    title
                }
            }
        }
    }
    """)

# This query succeeds because the `user` field is ignored
schema.execute("""
    query NotTooDeep {
        user(name:"matt") {
            favouriteBooks {
                author {
                    publishedBooks {
                        title
                    }
                }
            }
        }
    }
    """)
```

---

### Extensions Sentry Tracing (`docs/extensions/sentry-tracing.md`)

---
title: Sentry Tracing
summary: Add Sentry tracing to your GraphQL server.
tags: tracing
---

# `SentryTracingExtension`

<Warning>

As of Sentry 1.32.0, Strawberry is officially supported by the Sentry SDK.
Therefore, Strawberry's `SentryTracingExtension` has been deprecated in version
0.210.0 and finally removed with Strawberry 0.249.0 in favor of the official
Sentry SDK integration.

For more details, please refer to the
[documentation for the official Sentry Strawberry integration](https://docs.sentry.io/platforms/python/integrations/strawberry/).

</Warning>

## Filtering input coercion errors

The official Sentry integration captures all errors returned in a GraphQL
response. If invalid client input should not be reported, use Sentry's
`before_send` callback to filter `StrawberryInputCoercionError`:

```python
from typing import Any

import sentry_sdk

from strawberry.exceptions import StrawberryInputCoercionError


def before_send(event: dict[str, Any], hint: dict[str, Any]) -> dict[str, Any] | None:
    exc_info = hint.get("exc_info")
    error = exc_info[1] if exc_info else None

    if isinstance(error, StrawberryInputCoercionError) or isinstance(
        getattr(error, "original_error", None), StrawberryInputCoercionError
    ):
        return None

    return event


sentry_sdk.init(before_send=before_send)
```

Checking `original_error` is necessary because graphql-core wraps scalar errors
raised while coercing variables in another `GraphQLError`. For this reason,
Sentry's `ignore_errors` option alone does not filter every input coercion
error.

---

### Extensions Validation Cache (`docs/extensions/validation-cache.md`)

---
title: Validation Cache
summary: Add in memory caching to the validation step of query execution.
tags: performance,caching,validation
---

# `ValidationCache`

This extension adds LRU caching to the validation step of query execution to
improve performance by caching the validation errors in memory.

## Usage example:

```python
import strawberry
from strawberry.extensions import ValidationCache


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ValidationCache(),
    ],
)
```

## API reference:

```python
class ValidationCache(maxsize=128): ...
```

#### `maxsize: Optional[int] = 128`

Set the maxsize of the cache. By default the cache is bounded to 128 entries,
with the least recently used entries evicted first. Pass an explicit
`maxsize=None` to let the cache grow without bound; only do this when the set of
distinct query texts reaching the server is trusted and bounded, as an unbounded
cache lets clients grow the server's memory indefinitely by sending unique query
texts.

More info: https://docs.python.org/3/library/functools.html#functools.lru_cache

## More examples:

<details>
  <summary>Using maxsize</summary>

```python
import strawberry
from strawberry.extensions import ValidationCache


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello, world!"


schema = strawberry.Schema(
    Query,
    extensions=[
        ValidationCache(maxsize=100),
    ],
)
```

</details>

---

### Federation Custom Directives (`docs/federation/custom_directives.md`)

---
title: Exposing directives on the supergraph (Apollo Federation)
---

# Exposing directives on the supergraph (Apollo Federation)

By default (most)
[schema directives are hidden from the supergraph schema](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#composedirective).
If you need to expose a directive to the supergraph, you can use the `compose`
parameter on the `@strawberry.federation.schema_directives` decorator, here's an
example:

```python
import strawberry


@strawberry.federation.schema_directive(
    locations=[Location.OBJECT], name="cacheControl", compose=True
)
class CacheControl:
    max_age: int
```

This will create a `cacheControl` directive and it will also use
[`@composeDirective`](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#composedirective)
on the schema to make sure it is included in the supergraph schema.

---

### Federation Entities (`docs/federation/entities.md`)

---
title: Entities (Apollo Federation)
---

# Entities (Apollo Federation)

In a federated graph, an
[entity](https://www.apollographql.com/docs/federation/entities) is an object
type that can resolve its fields across multiple subgraphs.

Entities have a unique identifier, called a key, that is used to fetch them from
a subgraph. In Strawberry entities are defined by annotating a type with the
`@strawberry.federation.type` decorator, like in example below:

```python
import strawberry


@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    title: str
```

You can also use the `Key` directive manually, like so:

```python
import strawberry

from strawberry.federation.schema_directives import Key


@strawberry.type(directives=[Key(fields="id")])
class Book:
    id: strawberry.ID
    title: str
```

# Resolving references

When a GraphQL operation references an entity across multiple services, the
Apollo Router will fetch the entity from the subgraph that defines it. To do
this, the subgraph needs to be able to resolve the entity by its key. This is
done by defining a class method called `resolve_reference` on the entity type.

For example, if we have a `Book` entity type, we can define a
`resolve_reference` method like this:

```python
import strawberry


@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    title: str

    @classmethod
    def resolve_reference(cls, id: strawberry.ID) -> "Book":
        # here we could fetch the book from the database
        # or even from an API
        return Book(id=id, title="My Book")
```

Strawberry provides a default implementation of `resolve_reference` that
instantiates the object type using the data coming from the key. This means that
you can omit the `resolve_reference` method if you don't need to fetch any
additional data for your object type, like in the example below:

```python
import strawberry


@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    reviews_count: int = strawberry.field(resolver=lambda: 3)
```

In the example above we are creating an entity called `Book` that has a `title`
field and a `reviews_count` field. This entity will contribute to the `Book`
entity in the supergraph and it will provide the `reviews_count` field.

When the Apollo Router fetches the `Book` entity from this subgraph, it will
call the `resolve_reference` method with the `id` of the book and, as mentioned
above, Strawberry will instantiate the `Book` type using the data coming from
the key.

---

### Federation Entity Interfaces (`docs/federation/entity-interfaces.md`)

---
title: Entity interfaces (Apollo Federation)
---

# Extending interfaces

[Entity interfaces](https://www.apollographql.com/docs/federation/federated-types/interfaces)
are similar to [entities](./entities.md), but usually can't contribute new
fields to the supergraph (see below for how to use `@interfaceObject` to extend
interfaces).

Strawberry allows to define entity interfaces using the
`@strawberry.federation.interface` decorator, here's an example:

```python
import strawberry


@strawberry.federation.interface(keys=["id"])
class Media:
    id: strawberry.ID
```

This will generate the following GraphQL type:

```graphql
type Media @key(fields: "id") @interface {
  id: ID!
}
```

# Extending Entity interfaces (Apollo Federation)

In federation you can use `@interfaceObject` to extend interfaces from other
services. This is useful when you want to add fields to an interface that is
implemented by types in other services.

Entity interfaces that extend other interfaces are defined by annotating an
interface with the `@strawberry.federation.interface_object` decorator, like in
example below:

```python
import strawberry


@strawberry.federation.interface_object(keys=["id"])
class Media:
    id: strawberry.ID
    title: str
```

This will generate the following GraphQL type:

```graphql
type Media @key(fields: "id") @interfaceObject {
  id: ID!
  title: String!
}
```

`@strawberry.federation.interface_object` is necessary because if we were to
extend the `Media` interface using `@strawberry.federation.interface`, we'd need
to also define all the types implementing the interface, which will make the
schema hard to maintain (every updated to the interface and types implementing
it would need to be reflected in all subgraphs declaring it).

# Resolving references

Entity interfaces are also used to resolve references to entities. The same
rules as [entities](./entities.md) apply here. Here's a basic example:

```python
import strawberry


@strawberry.federation.interface_object(keys=["id"])
class Media:
    id: strawberry.ID
    title: str

    # TODO: check this

    @classmethod
    def resolve_reference(cls, id: strawberry.ID) -> "Media":
        # here we could fetch the media from the database
        # or even from an API
        return Media(id=id, title="My Media")
```

---

### Federation Introduction (`docs/federation/introduction.md`)

---
title: Apollo Federation
---

# Apollo Federation

Strawberry supports
[Apollo Federation](https://www.apollographql.com/docs/federation/) out of the
box, that means that you can create services using Strawberry and federate them
via Apollo Gateway or Apollo Router.

Strawberry is a schema first library, to use Apollo Federation you need to add
directives to your schema, types and fields. Strawberry has built support for
directives, but it also provide shortcuts for Apollo Federation.

All shortcuts live under the `strawberry.federation` module. For example if you
want to create an
[Entity](https://www.apollographql.com/docs/federation/entities) you can do:

```python
@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    title: str
```

And strawberry will automatically add the right directives to the type and
schema.

# Getting started

If you want to get started with Apollo Federation, you can use our
[Apollo Federation guide](../guides/federation.md).

---

### General Multipart Subscriptions (`docs/general/multipart-subscriptions.md`)

---
title: Multipart subscriptions
---

# Multipart subscriptions

Strawberry supports subscription over multipart responses. This is an
[alternative protocol](https://www.apollographql.com/docs/router/executing-operations/subscription-multipart-protocol/)
created by [Apollo](https://www.apollographql.com/) to support subscriptions
over HTTP, and it is supported by default by Apollo Client.

## Support

We support multipart subscriptions in the following HTTP libraries:

- Django (only in the Async view)
- ASGI
- Litestar
- FastAPI
- AioHTTP
- Quart

## Usage

Multipart subscriptions are opt-in. Enable them by including
`MULTIPART_SUBSCRIPTION_PROTOCOL` in your integration's
`subscription_protocols`:

```python
from strawberry.fastapi import GraphQLRouter
from strawberry.subscriptions import (
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
    MULTIPART_SUBSCRIPTION_PROTOCOL,
)

from api.schema import schema

graphql_router = GraphQLRouter(
    schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        MULTIPART_SUBSCRIPTION_PROTOCOL,
    ],
)
```

---

### General Mutations (`docs/general/mutations.md`)

---
title: Mutations
---

# Mutations

As opposed to queries, mutations in GraphQL represent operations that modify
server-side data and/or cause side effects on the server. For example, you can
have a mutation that creates a new instance in your application or a mutation
that sends an email. Like in queries, they accept parameters and can return
anything a regular field can, including new types and existing object types.
This can be useful for fetching the new state of an object after an update.

Let's improve our books project from the [Getting started tutorial](../index.md)
and implement a mutation that is supposed to add a book:

```python
import strawberry


# Reader, you can safely ignore Query in this example, it is required by
# strawberry.Schema so it is included here for completeness
@strawberry.type
class Query:
    @strawberry.field
    def hello() -> str:
        return "world"


@strawberry.type
class Mutation:
    @strawberry.mutation
    def add_book(self, title: str, author: str) -> Book:
        print(f"Adding {title} by {author}")

        return Book(title=title, author=author)


schema = strawberry.Schema(query=Query, mutation=Mutation)
```

Like queries, mutations are defined in a class that is then passed to the Schema
function. Here we create an `addBook` mutation that accepts a title and an
author and returns a `Book` type.

We would send the following GraphQL document to our server to execute the
mutation:

```graphql
mutation {
  addBook(title: "The Little Prince", author: "Antoine de Saint-Exupéry") {
    title
  }
}
```

The `addBook` mutation is a simplified example. In a real-world application
mutations will often need to handle errors and communicate those errors back to
the client. For example we might want to return an error if the book already
exists.

You can checkout our documentation on
[dealing with errors](/docs/guides/errors#expected-errors) to learn how to
return a union of types from a mutation.

## Mutations without returned data

It is also possible to write a mutation that doesn't return anything.

This is mapped to a `Void` GraphQL scalar, and always returns `null`

<CodeGrid>
```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    def restart() -> None:
        print(f"Restarting the server")
```

```graphql
type Mutation {
  restart: Void
}
```

</CodeGrid>

<Note>

Mutations with void-result go against
[this community-created guide on GQL best practices](https://github.com/graphql-rules/graphql-rules/blob/master/docs/rules/06-mutations/mutation-payload.md).

</Note>

## The input mutation extension

It is usually useful to use a pattern of defining a mutation that receives a
single [input type](../types/input-types) argument called `input`.

Strawberry provides the
[`InputMutationExtension`](../extensions/input-mutation.md), a
[field extension](../guides/field-extensions.md) that automatically creates an
input type for you, whose attributes are the same as the arguments in the
resolver.

For example, suppose we want the mutation defined in the section above to be an
input mutation. We can add the `InputMutationExtension` to the field like this:

```python
from strawberry.field_extensions import InputMutationExtension


@strawberry.type
class Mutation:
    @strawberry.mutation(extensions=[InputMutationExtension()])
    def update_fruit_weight(
        self,
        info: strawberry.Info,
        id: strawberry.ID,
        weight: Annotated[
            float,
            strawberry.argument(description="The fruit's new weight in grams"),
        ],
    ) -> Fruit:
        fruit = ...  # retrieve the fruit with the given ID
        fruit.weight = weight
        ...  # maybe save the fruit in the database
        return fruit
```

That would generate a schema like this:

```graphql
input UpdateFruitWeightInput {
  id: ID!

  """
  The fruit's new weight in grams
  """
  weight: Float!
}

type Mutation {
  updateFruitWeight(input: UpdateFruitWeightInput!): Fruit!
}
```

## Nested mutations

To avoid a graph becoming too large and to improve discoverability, it can be
helpful to group mutations in a namespace, as described by
[Apollo's guide on Namespacing by separation of concerns](https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern/).

```graphql
type Mutation {
  fruit: FruitMutations!
}

type FruitMutations {
  add(input: AddFruitInput): Fruit!
  updateWeight(input: UpdateFruitWeightInput!): Fruit!
}
```

Since all GraphQL operations are fields, we can define a `FruitMutation` type
and add mutation fields to it like we could add mutation fields to the root
`Mutation` type.

```python
import strawberry


@strawberry.type
class FruitMutations:
    @strawberry.mutation
    def add(self, info, input: AddFruitInput) -> Fruit: ...

    @strawberry.mutation
    def update_weight(self, info, input: UpdateFruitWeightInput) -> Fruit: ...


@strawberry.type
class Mutation:
    @strawberry.field
    def fruit(self) -> FruitMutations:
        return FruitMutations()
```

<Note>
Fields on the root `Mutation` type are resolved serially. Namespace types introduce the potential for mutations to be resolved asynchronously and in parallel because the mutation fields that mutate data are no longer at the root level.

To guarantee serial execution when namespace types are used, clients should use
aliases to select the root mutation field for each mutation. In the following
example, once `addFruit` execution is complete, `updateFruitWeight` begins.

```graphql
mutation (
  $addFruitInput: AddFruitInput!
  $updateFruitWeightInput: UpdateFruitWeightInput!
) {
  addFruit: fruit {
    add(input: $addFruitInput) {
      id
    }
  }

  updateFruitWeight: fruit {
    updateWeight(input: $updateFruitWeightInput) {
      id
    }
  }
}
```

For more details, see
[Apollo's guide on Namespaces for serial mutations](https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern/#namespaces-for-serial-mutations)
and
[Rapid API's Interactive Guide to GraphQL Queries: Aliases and Variables](https://rapidapi.com/guides/graphql-aliases-variables).

</Note>

---

### General Queries (`docs/general/queries.md`)

---
title: Queries
---

# Queries

In GraphQL you use queries to fetch data from a server. In Strawberry you can
define the data your server provides by defining query types.

By default all the fields the API exposes are nested under a root Query type.

This is how you define a root query type in Strawberry:

```python
@strawberry.type
class Query:
    name: str


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

This creates a schema where the root type Query has one single field called
name.

As you notice we don't provide a way to fetch data. In order to do so we need to
provide a `resolver`, a function that knows how to fetch data for a specific
field.

For example in this case we could have a function that always returns the same
name:

```python
def get_name() -> str:
    return "Strawberry"


@strawberry.type
class Query:
    name: str = strawberry.field(resolver=get_name)


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

So now, when requesting the name field, the `get_name` function will be called.

Alternatively a field can be declared using a decorator:

```python
@strawberry.type
class Query:
    @strawberry.field
    def name(self) -> str:
        return "Strawberry"
```

The decorator syntax supports specifying a `graphql_type` for cases when the
return type of the function does not match the GraphQL type:

```python
class User:
    id: str
    name: str

    def __init__(self, id: str, name: str):
        self.id = id
        self.name = name

@strawberry.type(name="User")
class UserType:
    id: strawberry.ID
    name: str

@strawberry.type
class Query:
    @strawberry.field(graphql_type=UserType)
    def user(self) -> User
        return User(id="ringo", name="Ringo")
```

## Arguments

GraphQL fields can accept arguments, usually to filter out or retrieve specific
objects:

```python
FRUITS = [
    "Strawberry",
    "Apple",
    "Orange",
]


@strawberry.type
class Query:
    @strawberry.field
    def fruit(self, startswith: str) -> str | None:
        for fruit in FRUITS:
            if fruit.startswith(startswith):
                return fruit
        return None
```

### Argument Descriptions

Use `Annotated` to give a field argument a description:

```python
from typing import Annotated
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def fruit(
        self,
        startswith: Annotated[
            str, strawberry.argument(description="Prefix to filter fruits by.")
        ],
    ) -> str | None: ...
```

### Argument Types

As with fields, `strawberry.argument` supports specifying a `graphql_type` for
cases when the argument type of the function does not match the GraphQL type.
This can be useful for static typing, as custom scalars are not valid type
annotations.

```python
BigInt = strawberry.scalar(
    int, name="BigInt", serialize=lambda v: str(v), parse_value=lambda v: int(v)
)


@strawberry.type
class Query:
    @strawberry.field
    def users(
        self,
        ids: Annotated[list[int], strawberry.argument(graphql_type=list[BigInt])],
    ) -> list[User]: ...
```

---

### General Schema Basics (`docs/general/schema-basics.md`)

---
title: Schema basics
---

# Schema basics

GraphQL servers use a **schema** to describe the shape of the data. The schema
defines a hierarchy of **types** with fields that are populated from data
stores. The schema also specifies exactly which queries and mutations are
available for clients to execute.

This guide describes the basic building blocks of a schema and how to use
Strawberry to create one.

## Schema definition language (SDL)

There are two approaches for creating the schema for a GraphQL server. One is
called “schema-first” and the other is called “code-first”. Strawberry _only_
supports code-first schemas. Before diving into code-first, let’s first explain
what the Schema definition language is.

Schema first works using the Schema Definition Language of GraphQL, which is
included in the GraphQL spec.

Here’s an example of schema defined using the SDL:

```graphql
type Book {
  title: String!
  author: Author!
}

type Author {
  name: String!
  books: [Book!]!
}
```

The schema defines all the types and relationships between them. With this we
enable client developers to see exactly what data is available and request a
specific subset of that data.

<Note>

The `!` sign specifies that a field is non-nullable.

</Note>

Notice that the schema doesn’t specify how to get the data. That comes later
when defining the resolvers.

## Code first approach

As mentioned Strawberry uses a code first approach. The previous schema would
look like this in Strawberry

```python
import typing
import strawberry


@strawberry.type
class Book:
    title: str
    author: "Author"


@strawberry.type
class Author:
    name: str
    books: typing.List[Book]
```

As you can see the code maps almost one to one with the schema, thanks to
python’s type hints feature.

Notice that here we are also not specifying how to fetch data, that will be
explained in the resolvers section.

## Supported types

GraphQL supports a few different types:

- Scalar types
- Object types
- The Query type
- The Mutation type
- Input types

## Scalar types



Scalar types are similar to Python primitive types. Here’s the list of the
default scalar types in GraphQL:

- Int, a signed 32-bit integer, maps to python’s int
- Float, a signed double-precision floating-point value, maps to python’s float
- String, maps to python’s str
- Boolean, true or false, maps to python’s bool
- ID, a unique identifier that usually used to refetch an object or as the key
  for a cache. Serialized as string and available as `strawberry.ID(“value”)`
- `UUID`, a [UUID](https://docs.python.org/3/library/uuid.html#uuid.UUID) value
  serialized as a string

<Note>

Strawberry also includes support for date, time and datetime objects, they are
not officially included with the GraphQL spec, but they are usually needed in
most servers. They are serialized as ISO-8601.

</Note>



These primitives work for the majority of use cases, but you can also specify
your [own scalar types](/docs/types/scalars#custom-scalars).

## Object types

Most of the types you define in a GraphQL schema are object types. An object
type contains a collection of fields, each of which can be either a scalar type
or another object type.

Object types can refer to each other, as we had in our schema earlier:

```python
import typing
import strawberry


@strawberry.type
class Book:
    title: str
    author: "Author"


@strawberry.type
class Author:
    name: str
    books: typing.List[Book]
```

## Providing data to fields

In the above schema, a `Book` has an `author` field and an `Author` has a
`books` field, yet we do not know how our data can be mapped to fulfil the
structure of the promised schema.

To achieve this, we introduce the concept of the
[_resolver_](../types/resolvers.md) that provides some data to a field through a
function.

Continuing with this example of books and authors, resolvers can be defined to
provide values to the fields:

```python
def get_author_for_book(root) -> "Author":
    return Author(name="Michael Crichton")


@strawberry.type
class Book:
    title: str
    author: "Author" = strawberry.field(resolver=get_author_for_book)


def get_books_for_author(root) -> typing.List[Book]:
    return [Book(title="Jurassic Park")]


@strawberry.type
class Author:
    name: str
    books: typing.List[Book] = strawberry.field(resolver=get_books_for_author)


def get_authors(root) -> typing.List[Author]:
    return [Author(name="Michael Crichton")]


@strawberry.type
class Query:
    authors: typing.List[Author] = strawberry.field(resolver=get_authors)
    books: typing.List[Book] = strawberry.field(resolver=get_books_for_author)
```

These functions provide the `strawberry.field` with the ability to render data
to the GraphQL query upon request and are the backbone of all GraphQL APIs.

This example is trivial since the resolved data is entirely static. However,
when building more complex APIs, these resolvers can be written to map data from
databases, e.g. making SQL queries using SQLAlchemy, and other APIs, e.g. making
HTTP requests using aiohttp.

For more information and detail on the different ways to write resolvers, see
the [resolvers section](../types/resolvers.md).

## The Query type

The `Query` type defines exactly which GraphQL queries (i.e., read operations)
clients can execute against your data. It resembles an object type, but its name
is always `Query`.

Each field of the `Query` type defines the name and return type of a different
supported query. The `Query` type for our example schema might resemble the
following:

```python
@strawberry.type
class Query:
    books: typing.List[Book]
    authors: typing.List[Author]
```

This Query type defines two available queries: books and authors. Each query
returns a list of the corresponding type.

With a REST-based API, books and authors would probably be returned by different
endpoints (e.g., /api/books and /api/authors). The flexibility of GraphQL
enables clients to query both resources with a single request.

### Structuring a query

When your clients build queries to execute against your data graph, those
queries match the shape of the object types you define in your schema.

Based on our example schema so far, a client could execute the following query,
which requests both a list of all book titles and a list of all author names:

```graphql
query {
  books {
    title
  }

  authors {
    name
  }
}
```

Our server would then respond to the query with results that match the query's
structure, like so:

```json
{
  "data": {
    "books": [{ "title": "Jurassic Park" }],
    "authors": [{ "name": "Michael Crichton" }]
  }
}
```

Although it might be useful in some cases to fetch these two separate lists, a
client would probably prefer to fetch a single list of books, where each book's
author is included in the result.

Because our schema's Book type has an author field of type Author, a client
could structure their query like so:

```graphql
query {
  books {
    title
    author {
      name
    }
  }
}
```

And once again, our server would respond with results that match the query's
structure:

```json
{
  "data": {
    "books": [
      { "title": "Jurassic Park", "author": { "name": "Michael Crichton" } }
    ]
  }
}
```

## The Mutation type

The `Mutation` type is similar in structure and purpose to the Query type.
Whereas the Query type defines your data's supported read operations, the
`Mutation` type defines supported write operations.

Each field of the `Mutation` type defines the signature and return type of a
different mutation. The `Mutation` type for our example schema might resemble
the following:

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    def add_book(self, title: str, author: str) -> Book: ...
```

This Mutation type defines a single available mutation, `addBook`. The mutation
accepts two arguments (title and author) and returns a newly created Book
object. As you'd expect, this Book object conforms to the structure that we
defined in our schema.

<Note>

Strawberry converts fields names from snake case to camel case by default. This
can be changed by specifying a
[custom `StrawberryConfig` on the schema](../types/schema-configurations.md)

</Note>

### Structuring a mutation

Like queries, mutations match the structure of your schema's type definitions.
The following mutation creates a new Book and requests certain fields of the
created object as a return value:

```graphql
mutation {
  addBook(title: "Fox in Socks", author: "Dr. Seuss") {
    title
    author {
      name
    }
  }
}
```

As with queries, our server would respond to this mutation with a result that
matches the mutation's structure, like so:

```json
{
  "data": {
    "addBook": {
      "title": "Fox in Socks",
      "author": {
        "name": "Dr. Seuss"
      }
    }
  }
}
```

## Input types

Input types are special object types that allow you to pass objects as arguments
to queries and mutations (as opposed to passing only scalar types). Input types
help keep operation signatures clean.

Consider our previous mutation to add a book:

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    def add_book(self, title: str, author: str) -> Book: ...
```

Instead of accepting two arguments, this mutation could accept a single input
type that includes all of these fields. This comes in extra handy if we decide
to accept an additional argument in the future, such as a publication date.

An input type's definition is similar to an object type's, but it uses the input
keyword:

```python
@strawberry.input
class AddBookInput:
    title: str
    author: str


@strawberry.type
class Mutation:
    @strawberry.mutation
    def add_book(self, book: AddBookInput) -> Book: ...
```

Not only does this facilitate passing the AddBookInput type around within our
schema, it also provides a basis for annotating fields with descriptions that
are automatically exposed by GraphQL-enabled tools:

```python
@strawberry.input
class AddBookInput:
    title: str = strawberry.field(description="The title of the book")
    author: str = strawberry.field(description="The name of the author")
```

Input types can sometimes be useful when multiple operations require the exact
same set of information, but you should reuse them sparingly. Operations might
eventually diverge in their sets of required arguments.

## More

If you want to learn more about schema design make sure you follow the
[documentation provided by Apollo](https://www.apollographql.com/docs/apollo-server/schema/schema/#growing-with-a-schema).

---

### General Subscriptions (`docs/general/subscriptions.md`)

---
title: Subscriptions
---

# Subscriptions

In GraphQL you can use subscriptions to stream data from a server. To enable
this with Strawberry, use an integration that supports a streaming transport
such as websockets, multipart HTTP, or Server-Sent Events (SSE).

This is how you define a subscription-capable resolver:

```python
import asyncio
from typing import AsyncGenerator

import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def count(self, target: int = 100) -> AsyncGenerator[int, None]:
        for i in range(target):
            yield i
            await asyncio.sleep(0.5)


schema = strawberry.Schema(query=Query, subscription=Subscription)
```

Like queries and mutations, subscriptions are defined in a class and passed to
the Schema function. Here we create a rudimentary counting function which counts
from 0 to the target sleeping between each loop iteration.

<Note>

The return type of `count` is `AsyncGenerator` where the first generic argument
is the actual type of the response, in most cases the second argument should be
left as `None` (more about Generator typing
[here](https://docs.python.org/3/library/typing.html#typing.AsyncGenerator)).

</Note>

We would send the following GraphQL document to our server to subscribe to this
data stream:

```graphql
subscription {
  count(target: 5)
}
```

In this example, the data looks like this as it passes over the websocket:



This is a very short example of what is possible. Like with queries and
mutations the subscription can return any GraphQL type, not only scalars as
demonstrated here.

## Authenticating Subscriptions

Without going into detail on [why](https://github.com/websockets/ws/issues/467),
custom headers cannot be set on websocket requests that originate in browsers.
Therefore, when making any GraphQL requests that rely on a websocket connection,
header-based authentication is impossible.

Other popular GraphQL solutions, like Apollo for example, implement
functionality to pass information from the client to the server at the point of
websocket connection initialisation. In this way, information that is relevant
to the websocket connection initialisation and to the lifetime of the connection
overall can be passed to the server before any data is streamed back by the
server. As such, it is not limited to only authentication credentials!

Strawberry's implementation follows that of Apollo's, which as documentation for
[client](https://www.apollographql.com/docs/react/data/subscriptions/#5-authenticate-over-websocket-optional)
and
[server](https://www.apollographql.com/docs/apollo-server/data/subscriptions/#operation-context)
implementations, by reading the contents of the initial websocket connection
message into the `info.context` object.

With Apollo-client as an example of how to send this initial connection
information, one defines a `ws-link` as:

```javascript
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";

const wsLink = new GraphQLWsLink(
  createClient({
    url: "ws://localhost:4000/subscriptions",
    connectionParams: {
      authToken: "Bearer I_AM_A_VALID_AUTH_TOKEN",
    },
  }),
);
```

and then, upon the establishment of the Susbcription request and underlying
websocket connection, Strawberry injects this `connectionParams` object as
follows:

```python
import asyncio
from typing import AsyncGenerator

import strawberry

from .auth import authenticate_token


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def count(
        self, info: strawberry.Info, target: int = 100
    ) -> AsyncGenerator[int, None]:
        connection_params: dict = info.context.get("connection_params")
        token: str = connection_params.get(
            "authToken"
        )  # equal to "Bearer I_AM_A_VALID_AUTH_TOKEN"
        if not authenticate_token(token):
            raise Exception("Forbidden!")
        for i in range(target):
            yield i
            await asyncio.sleep(0.5)


schema = strawberry.Schema(query=Query, subscription=Subscription)
```

Strawberry expects the `connection_params` object to be any type, so the client
is free to send any valid JSON object as the initial message of the websocket
connection, which is abstracted as `connectionParams` in Apollo-client, and it
will be successfully injected into the `info.context` object. It is then up to
you to handle it correctly!

## Using SSE Subscriptions

Server-Sent Events (SSE) are an HTTP-based alternative to websockets for
server-to-client streaming. SSE is opt-in; enable it by including
`GRAPHQL_SSE_PROTOCOL` in your integration's `subscription_protocols`:

```python
from strawberry.asgi import GraphQL
from strawberry.subscriptions import (
    GRAPHQL_SSE_PROTOCOL,
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
)

from api.schema import schema

app = GraphQL(
    schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        GRAPHQL_SSE_PROTOCOL,
    ],
)
```

Then request an SSE response by sending a normal GraphQL HTTP request with
`Accept: text/event-stream`:

```http
POST /graphql
Accept: text/event-stream
Content-Type: application/json

{"query": "subscription { count(target: 5) }"}
```

Strawberry sends each execution result as a `next` event and sends a `complete`
event when the operation finishes:

```text
event: next
data: {"data": {"count": 0}}

event: complete
data:
```

Most applications should use a GraphQL SSE client rather than parsing the event
stream directly. For example, with
[`graphql-sse`](https://github.com/enisdenjo/graphql-sse):

```javascript
import { createClient } from "graphql-sse";

const client = createClient({
  url: "http://localhost:8000/graphql",
});

const dispose = client.subscribe(
  {
    query: "subscription { count(target: 5) }",
  },
  {
    next: (result) => {
      console.log(result.data);
    },
    error: console.error,
    complete: () => {
      console.log("done");
    },
  },
);

// Call this when the UI no longer needs the subscription.
dispose();
```

<Note>

**Prefer HTTP/2 for SSE.** Strawberry uses one SSE response per operation. When
browsers connect over HTTP/1.x they allow only a small number of concurrent
connections to the same origin (commonly six), so multiple long-lived
subscriptions — across tabs, or alongside other requests to the same origin —
can exhaust that limit and stall the page. HTTP/2 multiplexes many streams over
a single connection and removes this bottleneck.

Most ASGI servers, including `uvicorn`, serve HTTP/1.1 only, so HTTP/2 is
typically provided by a reverse proxy (such as Nginx, Caddy, or a cloud load
balancer) terminating in front of your app. If you cannot run HTTP/2, prefer
websockets for subscriptions that need several concurrent streams.

</Note>

Strawberry also sends SSE comment heartbeats on idle streams. SSE clients ignore
comment lines, but they keep intermediaries from closing long-lived connections
that have not produced a GraphQL result recently.

SSE responses are sent with `Cache-Control: no-cache, no-transform` and
`X-Accel-Buffering: no` so that Nginx and similar proxies do not buffer or
compress the stream. Response-compression middleware running inside your own
application — such as Starlette/FastAPI's `GZipMiddleware` or a brotli
middleware — buffers the response before it reaches those proxies and will break
real-time delivery and heartbeats regardless of these headers. Exclude your
GraphQL/SSE routes from such middleware.

### Limitations

<Note>

**Distinct connections mode only.** The
[GraphQL over SSE protocol](https://github.com/enisdenjo/graphql-sse/blob/master/PROTOCOL.md)
defines two modes. Strawberry implements the
["distinct connections mode"](https://github.com/enisdenjo/graphql-sse/blob/master/PROTOCOL.md#distinct-connections-mode),
where each operation gets its own SSE response. This is the default for the
`graphql-sse` client; the multiplexed
["single connection mode"](https://github.com/enisdenjo/graphql-sse/blob/master/PROTOCOL.md#single-connection-mode)
(`createClient({ singleConnection: true })`, which reserves a token over `PUT`
and routes operations through one stream) is **not** supported.

</Note>

SSE responses are streamed and therefore require an async integration that
supports streaming responses: ASGI, FastAPI, AIOHTTP, Litestar, Quart, Sanic,
async Django, and async Channels. The Flask (sync and async), Chalice, sync
Django, and sync Channels integrations cannot stream SSE.

By default Strawberry does not set an `id` field on events, so a dropped
connection means starting a new subscription operation. If your event source is
resumable, you can opt into reconnection support — see
[Resuming after a reconnect](#resuming-after-a-reconnect).

### Authenticating SSE subscriptions

SSE subscriptions use normal HTTP requests. Unlike websockets, browser SSE
clients can send HTTP authentication data such as cookies, query parameters,
and, when using a client based on `fetch`, custom headers like `Authorization`.
Native `EventSource` does not allow custom headers, so use cookies, query
parameters, or a `fetch`-based GraphQL SSE client when you need header-based
authentication in the browser.

Use your integration's `get_context` hook for SSE authentication, like you would
for queries and mutations:

```python
from starlette.requests import Request
from starlette.responses import Response

from strawberry.asgi import GraphQL


class AuthenticatedGraphQL(GraphQL):
    async def get_context(self, request: Request, response: Response):
        return {
            "request": request,
            "response": response,
            "token": request.headers.get("Authorization"),
        }
```

Then read the value from `info.context` in your resolver:

```python
import asyncio
from typing import AsyncGenerator

import strawberry

from .auth import authenticate_token


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def count(
        self, info: strawberry.Info, target: int = 100
    ) -> AsyncGenerator[int, None]:
        token = info.context["token"]
        if not authenticate_token(token):
            raise Exception("Forbidden!")

        for i in range(target):
            yield i
            await asyncio.sleep(0.5)
```

`on_ws_connect` and `connection_params` are websocket-specific APIs. SSE does
not have a separate connection initialisation message, so Strawberry does not
call a separate SSE connect hook.

### Resuming after a reconnect

Strawberry never buffers or replays past results, but if your event source is
resumable (a message broker with offsets, a database cursor, and so on) you can
let clients resume after a dropped connection.

A reconnecting client sends the id of the last event it received in the
`Last-Event-ID` request header. Since SSE is a normal HTTP request, read that
header from the request — which integrations already place in the context — and
resume from it:

```python
@strawberry.type
class Subscription:
    @strawberry.subscription
    async def notifications(
        self, info: strawberry.Info
    ) -> AsyncGenerator[Notification, None]:
        request = info.context["request"]
        cursor = request.headers.get("last-event-id")  # None on first connect

        async for notification in stream_notifications(after=cursor):
            yield notification
```

<Note>

Like the [`graphql-sse`](https://github.com/enisdenjo/graphql-sse) reference
implementation, Strawberry does not emit SSE `id:` lines, so the native browser
`EventSource` (which resends `Last-Event-ID` only from server-sent `id:` lines)
will not resume automatically. This is for clients that carry a cursor in the
GraphQL data itself and set `Last-Event-ID` on reconnect.

</Note>

## Advanced Subscription Patterns

Typically a GraphQL subscription is streaming something more interesting back.
With that in mind your subscription function can return one of:

- `AsyncIterator`, or
- `AsyncGenerator`

Both of these types are documented in [PEP-525][pep-525]. Anything yielded from
these types of resolvers will be shipped across the websocket. Care needs to be
taken to ensure the returned values conform to the GraphQL schema.

The benefit of an AsyncGenerator, over an iterator, is that the complex business
logic can be broken out into a separate module within your codebase. Allowing
you to keep the resolver logic succinct.

The following example is similar to the one above, except it returns an
AsyncGenerator to the ASGI server which is responsible for streaming
subscription results until the Generator exits.

```
/* Detailed source-code truncated for AI context efficiency. */
```

[pep-525]: https://www.python.org/dev/peps/pep-0525/

## Unsubscribing subscriptions

In GraphQL, it is possible to unsubscribe from a subscription. Strawberry
supports this behaviour, and is done using a `try...except` block.

In Apollo-client, closing a subscription can be achieved like the following:

```javascript
const client = useApolloClient();
const subscriber = client.subscribe({query: ...}).subscribe({...})
// ...
// done with subscription. now unsubscribe
subscriber.unsubscribe();
```

Strawberry can capture when a subscriber unsubscribes using an
`asyncio.CancelledError` exception.

```python
import asyncio
from typing import AsyncGenerator
from uuid import uuid4

import strawberry

# track active subscribers
event_messages = {}


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def message(self) -> AsyncGenerator[int, None]:
        try:
            subscription_id = uuid4()

            event_messages[subscription_id] = []

            while True:
                if len(event_messages[subscription_id]) > 0:
                    yield event_messages[subscription_id]
                    event_messages[subscription_id].clear()

                await asyncio.sleep(1)
        except asyncio.CancelledError:
            # stop listening to events
            del event_messages[subscription_id]
```

## Subscription Protocols

Strawberry supports both the legacy
[graphql-ws](https://github.com/apollographql/subscriptions-transport-ws) and
the newer recommended
[graphql-transport-ws](https://github.com/enisdenjo/graphql-ws) WebSocket
sub-protocols. Strawberry also supports GraphQL over SSE through
`GRAPHQL_SSE_PROTOCOL`.

<Note>

The `graphql-transport-ws` protocols repository is called `graphql-ws`. However,
`graphql-ws` is also the name of the legacy protocol. This documentation always
refers to the protocol names.

</Note>

Note that the `graphql-ws` sub-protocol is mainly supported for backwards
compatibility. Read the
[graphql-ws-transport protocols announcement](https://the-guild.dev/blog/graphql-over-websockets)
to learn more about why the newer protocol is preferred.

Strawberry allows you to choose which protocols you want to accept. All
integrations supporting subscriptions can be configured with a list of
`subscription_protocols` to accept. By default, the websocket protocols are
accepted. Multipart subscriptions and SSE are opt-in.

### AIOHTTP

```python
from strawberry.aiohttp.views import GraphQLView
from strawberry.subscriptions import (
    GRAPHQL_SSE_PROTOCOL,
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
)
from api.schema import schema

view = GraphQLView(
    schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        GRAPHQL_SSE_PROTOCOL,
    ],
)
```

### ASGI

```python
from strawberry.asgi import GraphQL
from strawberry.subscriptions import (
    GRAPHQL_SSE_PROTOCOL,
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
)
from api.schema import schema

app = GraphQL(
    schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        GRAPHQL_SSE_PROTOCOL,
    ],
)
```

### Django + Channels

```python
import os

from django.core.asgi import get_asgi_application
from strawberry.channels import GraphQLProtocolTypeRouter
from strawberry.subscriptions import (
    GRAPHQL_SSE_PROTOCOL,
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django_asgi_app = get_asgi_application()

# Import your Strawberry schema after creating the django ASGI application
# This ensures django.setup() has been called before any ORM models are imported
# for the schema.
from mysite.graphql import schema

application = GraphQLProtocolTypeRouter(
    schema,
    django_application=django_asgi_app,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        GRAPHQL_SSE_PROTOCOL,
    ],
)
```

Note: Check the [channels integraton](../integrations/channels.md) page for more
information regarding it.

### FastAPI

```python
from strawberry.fastapi import GraphQLRouter
from strawberry.subscriptions import (
    GRAPHQL_SSE_PROTOCOL,
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
)
from fastapi import FastAPI
from api.schema import schema

graphql_router = GraphQLRouter(
    schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        GRAPHQL_SSE_PROTOCOL,
    ],
)

app = FastAPI()
app.include_router(graphql_router, prefix="/graphql")
```

### Quart

```python
from strawberry.quart.views import GraphQLView
from strawberry.subscriptions import (
    GRAPHQL_SSE_PROTOCOL,
    GRAPHQL_TRANSPORT_WS_PROTOCOL,
    GRAPHQL_WS_PROTOCOL,
)
from quart import Quart
from api.schema import schema

view = GraphQLView.as_view(
    "graphql_view",
    schema=schema,
    subscription_protocols=[
        GRAPHQL_TRANSPORT_WS_PROTOCOL,
        GRAPHQL_WS_PROTOCOL,
        GRAPHQL_SSE_PROTOCOL,
    ],
)

app = Quart(__name__)
app.add_url_rule(
    "/graphql",
    view_func=view,
    methods=["GET"],
    websocket=True,
)
```

## Single result operations

In addition to _streaming operations_ (i.e. subscriptions), the
`graphql-transport-ws` protocol supports so called _single result operations_
(i.e. queries and mutations).

This enables clients to use one protocol and one connection for queries,
mutations and subscriptions. Take a look at the
[protocol's repository](https://github.com/enisdenjo/graphql-ws) to learn how to
correctly set up the graphql client of your choice.

Strawberry supports single result operations out of the box when the
`graphql-transport-ws` protocol is enabled. Single result operations are normal
queries and mutations, so there is no need to adjust any resolvers.

---

### General Upgrades (`docs/general/upgrades.md`)

---
title: Upgrading Strawberry
---

# Upgrading Strawberry



We try to keep Strawberry as backwards compatible as possible, but sometimes we
need to make updates to the public API. While we try to deprecate APIs before
removing them, we also want to make it as easy as possible to upgrade to the
latest version of Strawberry.

For this reason, we provide a CLI command to run Codemods that can automatically
upgrade your codebase to use the updated APIs.

Keep an eye on our release notes and the
[breaking changes](../breaking-changes.md) page to see if a new Codemod is
available, or if manual changes are required.

Here's an example of how to upgrade your codebase by running a Codemod using the
Strawberry CLI's `upgrade` command:

```shell
strawberry upgrade annotated-union .
```

---

### Guides Accessing Parent Data (`docs/guides/accessing-parent-data.md`)

---
title: Accessing parent's data in resolvers
---

# Accessing parent's data in resolvers

It is quite common to want to be able to access the data from the field's parent
in a resolver. For example let's say that we want to define a `fullName` field
on our `User`. This would be our code:

<CodeGrid>

```python
import strawberry


@strawberry.type
class User:
    first_name: str
    last_name: str
    full_name: str
```

```graphql
type User {
  firstName: String!
  lastName: String!
  fullName: String!
}
```

</CodeGrid>

In this case `full_name` will need to access the `first_name` and `last_name`
fields, and depending on whether we define the resolver as a function or as a
method, we'll have a few options! Let's start with the defining a resolver as a
function.

## Accessing parent's data in function resolvers

```python
import strawberry


def get_full_name() -> str: ...


@strawberry.type
class User:
    first_name: str
    last_name: str
    full_name: str = strawberry.field(resolver=get_full_name)
```

Our resolver is a function with no arguments, in order to tell Strawberry to
pass us the parent of the field, we need to add a new argument with type
`strawberry.Parent[ParentType]`, like so:

```python
def get_full_name(parent: strawberry.Parent[User]) -> str:
    return f"{parent.first_name} {parent.last_name}"
```

`strawberry.Parent` tells Strawberry to pass the parent value of the field, in
this case it would be the `User`.

> **Note:** `strawberry.Parent` accepts a type argument, which will then be used
> by your type checker to check your code!

### Using root

Historically Strawberry only supported passing the parent value by adding a
parameter called `root`:

```python
def get_full_name(root: User) -> str:
    return f"{root.first_name} {root.last_name}"
```

This is still supported, but we recommend using `strawberry.Parent`, since it
follows Strawberry's philosophy of using type annotations. Also, with
`strawberry.Parent` your argument can have any name, for example this will still
work:

```python
def get_full_name(user: strawberry.Parent[User]) -> str:
    return f"{user.first_name} {user.last_name}"
```

## Accessing parent's data in a method resolver

Both options also work when defining a method resolver, so we can still use
`strawberry.Parent` in a resolver defined as a method:

```python
import strawberry


@strawberry.type
class User:
    first_name: str
    last_name: str

    @strawberry.field
    def full_name(self, parent: strawberry.Parent[User]) -> str:
        return f"{parent.first_name} {parent.last_name}"
```

But, here's where things get more interesting. If this was a pure Python class,
we would use `self` directly, right? Turns out that Strawberry also supports
this!

Let's update our resolver:

```python
import strawberry


@strawberry.type
class User:
    first_name: str
    last_name: str

    @strawberry.field
    def full_name(self) -> str:
        return f"{self.first_name} {self.last_name}"
```

Much better, no? `self` on resolver methods is pretty convenient, and it works
like it should in Python, but there might be cases where it doesn't properly
follow Python's semantics. This is because under the hood resolvers are actually
called as if they were static methods by Strawberry.

Let's see a simplified version of what happens when you request the `full_name`
field, to do that we also need a field that allows to fetch a user:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def user(self) -> User:
        return User(first_name="Albert", last_name="Heijn")
```

When we do a query like this:

```graphql
{
  user {
    fullName
  }
}
```

We are pretty much asking to call the `user` function on the `Query` class, and
then call the `full_name` function on the `User` class, similar to this code:

```python
user = Query().user()

full_name = user.full_name()
```

While this might work for this case, it won't work in other cases, like when
returning a different type, for example when fetching the user from a database:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def user(self) -> User:
        # let's assume UserModel fetches data from the db and it
        # also has `first_name` and `last_name`
        user = UserModel.objects.first()

        return user
```

In this case our pseudo code would break, since `UserModel` doesn't have a
`full_name` function! But it does work when using Strawberry (provided that the
`UserModel` has both `first_name` and `last_name` fields).

As mentioned, this is because Strawberry class the resolvers as if they were
plain functions (not bound to the class), similar to this:

```python
# note, we are not instantiating the Query any more!
user = Query.user()  # note: this is a `UserModel` now

full_name = User.full_name(user)
```

You're probably thinking of `staticmethod`s and that's pretty much what we are
dealing with now! If you want to keep the resolver as a method on your class but
also want to remove some of the magic around `self`, you can use the
`@staticmethod` decorator in combination with `strawberry.Parent`:

```python
import strawberry


@strawberry.type
class User:
    first_name: str
    last_name: str

    @strawberry.field
    @staticmethod
    def full_name(parent: strawberry.Parent[User]) -> str:
        return f"{parent.first_name} {parent.last_name}"
```

Combining `@staticmethod` with `strawberry.Parent` is a good way to make sure
that your code is clear and that you are aware of what's happening under the
hood, and it will keep your linters and type checkers happy!

---

### Guides Authentication (`docs/guides/authentication.md`)

---
title: Authentication
---

# Authentication

Authentication is the process of verifying that a user is who they claim to be
and should be handled by the framework you are using. Some already have a
built-in authentication system (like Django); others, you have to provide it
manually. It's not Strawberry's responsibility to authenticate the user, but it
can be used to create a mutation that handles the authentication's process. It's
also very important not to confuse authentication with authorization:
authorization determines what an authenticated user can do or which data they
can access. In Strawberry, this is managed with
[`Permissions` classes](./permissions.md).

Let's see how to put together these concepts with an example. First, we define a
`login` mutation where we authenticate credentials and return `LoginSucces` or
`LoginError` types depending on whether the user was successfully authenticated
or not.

```python
import strawberry
from .types import User

from typing import Annotated, Union


@strawberry.type
class LoginSuccess:
    user: User


@strawberry.type
class LoginError:
    message: str


LoginResult = Annotated[
    Union[LoginSuccess, LoginError], strawberry.union("LoginResult")
]


@strawberry.type
class Mutation:
    @strawberry.field
    def login(self, username: str, password: str) -> LoginResult:
        # Your domain-specific authentication logic would go here
        user = your_authorization_service.login(username, password)

        if user is None:
            return LoginError(message="Something went wrong")

        return LoginSuccess(user=User(username=username))
```

### Access authenticated user in resolver

Its fairly common to require user information within a resolver. We can do that
in a type safe way with a custom context dataclass.

For example, in FastAPI this might look like this:

```python
from functools import cached_property

import strawberry
from fastapi import FastAPI
from strawberry.fastapi import BaseContext, GraphQLRouter


@strawberry.type
class User: ...  # This is just a stub for an actual user object


class Context(BaseContext):
    @cached_property
    def user(self) -> User | None:
        if not self.request:
            return None

        authorization = self.request.headers.get("Authorization", None)
        # Your domain-specific authentication logic would go here
        return your_authorization_service.authorize(authorization)


@strawberry.type
class Query:
    @strawberry.field
    def get_authenticated_user(self, info: strawberry.Info[Context]) -> User | None:
        return info.context.user


async def get_context() -> Context:
    return Context()


schema = strawberry.Schema(Query)


graphql_app = GraphQLRouter(
    schema,
    context_getter=get_context,
)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

---

### Guides Convert To Dictionary (`docs/guides/convert-to-dictionary.md`)

---
title: Convert to Dictionary
---

# Convert to Dictionary

Strawberry provides a utility function to convert a Strawberry object to a
dictionary.

You can use `strawberry.asdict(...)` function:

```python
@strawberry.type
class User:
    name: str
    age: int


# should be {"name": "Lorem", "age": 25}
user_dict = strawberry.asdict(User(name="Lorem", age=25))
```

## Handling of `Maybe` and `UNSET` values

When using [`Maybe`](../types/maybe.md) fields, `strawberry.asdict` unwraps the
value of that field, if present.

- A `Maybe` field that is absent is excluded from output.
- A field that returns `Some(None)`, an explicit null, is included with the
  value `None`.
- A field that returns `UNSET` is excluded from output.

```python
import strawberry
from strawberry import UNSET, Maybe, Some, asdict


@strawberry.input
class Input:
    field_a: Maybe[str | None]
    field_b: Maybe[str | None]
    field_c: Maybe[str | None]
    field_d: Maybe[str | None]


# should be {"field_a": "hello", field_b=None}
# `field_c` is excluded because it is an absent `Maybe` instead of an explicit null;
# `field_d` is excluded because it is UNSET
input_dict = asdict(
    Input(
        field_a=Some("hello"),
        field_b=Some(None),
        field_c=None,
        field_d=UNSET,
    )
)
```

---

### Guides Custom Extensions (`docs/guides/custom-extensions.md`)

---
title: Schema extensions
---

# Schema extensions

Strawberry provides support for adding extensions to your schema. Schema
extensions can be used to hook into different parts of the GraphQL execution and
to provide additional results to the GraphQL response.

To create a custom extension you can extend from our `SchemaExtension` base
class:

```python
import strawberry
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def get_results(self):
        return {"example": "this is an example for an extension"}


schema = strawberry.Schema(query=Query, extensions=[MyExtension])
```

## Passing extensions

Extensions can be passed to the schema as either:

- a **class** (no constructor arguments):

  ```python
  import strawberry
  from strawberry.extensions import MyExtension

  schema = strawberry.Schema(query=Query, extensions=[MyExtension])
  ```

- a **factory** (configured constructor):

  ```python
  import strawberry
  from strawberry.extensions import MaxTokensLimiter

  schema = strawberry.Schema(
      query=Query,
      extensions=[lambda: MaxTokensLimiter(max_token_count=100)],
  )
  ```

In both cases Strawberry calls the class or the factory once per request and
uses the returned extension. With the recommended forms above you get a fresh
extension per request, so any mutable state you keep on `self` is automatically
isolated across concurrent requests. If your factory returns a long-lived shared
instance instead of a new one each call, request-scoped state on `self`
(including `execution_context`) will leak across concurrent requests. Keep
cross-request state in module-level or class-level storage instead.

> Passing an extension instance directly (`extensions=[MyExtension()]`) is
> deprecated and is no longer accepted by the type signature, so type checkers
> (mypy, pyright) will report it. Strawberry still uses the instance at runtime
> for backwards compatibility and emits a `DeprecationWarning`, but the same
> instance is reused for every request, so concurrent requests can observe each
> other's `ExecutionContext`. Migrate to passing the class or a factory callable
> to silence the warning and get per-request isolation.

## Hooks

### Resolve

`resolve` can be used to run code before and after the execution of **all**
resolvers. When calling the underlying resolver using `_next`, all of the
arguments to resolve need to be passed to `_next`, as they will be needed by the
resolvers.

If you need to wrap only certain field resolvers with additional logic, please
check out [field extensions](field-extensions.md).

Note that `resolve` can also be implemented asynchronously.

```python
from graphql import GraphQLResolveInfo
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def resolve(self, _next, root, info: GraphQLResolveInfo, *args, **kwargs):
        return _next(root, info, *args, **kwargs)
```

### Get results

`get_results` allows to return a dictionary of data or alternatively an
awaitable resolving to a dictionary of data that will be included in the GraphQL
response.

```python
from typing import Any, Dict
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def get_results(self) -> Dict[str, Any]:
        return {}
```

### Lifecycle hooks

Lifecycle hooks runs before graphql operation occur and after it is done.
Lifecycle hooks uses generator syntax. In example: `on_operation` hook can be
used to run code when a GraphQL operation starts and ends.

```python
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def on_operation(self):
        print("GraphQL operation start")
        yield
        print("GraphQL operation end")
```

<details>
  <summary>Extend error response format</summary>

```python
class ExtendErrorFormat(SchemaExtension):
    def on_operation(self):
        yield
        result = self.execution_context.result
        if getattr(result, "errors", None):
            result.errors = [
                StrawberryGraphQLError(
                    extensions={"additional_key": "additional_value"},
                    nodes=error.nodes,
                    source=error.source,
                    positions=error.positions,
                    path=error.path,
                    original_error=error.original_error,
                    message=error.message,
                )
                for error in result.errors
            ]


@strawberry.type
class Query:
    @strawberry.field
    def ping(self) -> str:
        raise Exception("This error occurred while querying the ping field")


schema = strawberry.Schema(query=Query, extensions=[ExtendErrorFormat])
```

</details>

#### Supported lifecycle hooks:

- Validation

`on_validate` can be used to run code on the validation step of the GraphQL
execution.

```python
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def on_validate(self):
        print("GraphQL validation start")
        yield
        print("GraphQL validation end")
```

- Parse

`on_parse` can be used to run code on the parsing step of the GraphQL execution.

```python
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def on_parse(self):
        print("GraphQL parsing start")
        yield
        print("GraphQL parsing end")
```

- Execution

`on_execute` can be used to run code on the execution step of the GraphQL
execution.

```python
from strawberry.extensions import SchemaExtension


class MyExtension(SchemaExtension):
    def on_execute(self):
        print("GraphQL execution start")
        yield
        print("GraphQL execution end")
```

- Stream result

`on_stream_result` wraps each result yielded by `Schema.stream`, including
subscription events, queries or mutations executed over WebSockets, SSE, or
multipart responses. On transports that support experimental incremental
execution, it also wraps the delivery frames produced by `@defer` or `@stream`.
It can inspect or mutate a result before the transport sends it and run cleanup
after the transport consumes it.

`Schema.subscribe` uses the same streaming path, so this hook runs for every
subscription event. With experimental incremental execution enabled, it also
runs for every `@defer` or `@stream` response frame: an initial result followed
by subsequent patches.

```python
from collections.abc import Iterator

from strawberry.extensions import SchemaExtension
from strawberry.types import StreamExecutionResult


class MyExtension(SchemaExtension):
    def on_stream_result(self, result: StreamExecutionResult) -> Iterator[None]:
        print("GraphQL stream result ready", result)
        yield
        print("GraphQL stream result consumed", result)
```

#### Examples:

<details>
  <summary>In memory cached execution</summary>

```python
import json
import strawberry
from strawberry.extensions import SchemaExtension

# Use an actual cache in production so that this doesn't grow unbounded
response_cache = {}


class ExecutionCache(SchemaExtension):
    def on_execute(self):
        # Check if we've come across this query before
        execution_context = self.execution_context
        self.cache_key = (
            f"{execution_context.query}:{json.dumps(execution_context.variables)}"
        )
        if self.cache_key in response_cache:
            self.execution_context.result = response_cache[self.cache_key]
        yield
        execution_context = self.execution_context
        if self.cache_key not in response_cache:
            response_cache[self.cache_key] = execution_context.result


schema = strawberry.Schema(
    Query,
    extensions=[
        ExecutionCache,
    ],
)
```

</details>

<details>
  <summary>Rejecting an operation before executing it</summary>

```python
import strawberry
from strawberry.extensions import SchemaExtension


class RejectSomeQueries(SchemaExtension):
    def on_execute(self):
        # Reject all operations called "RejectMe"
        execution_context = self.execution_context
        if execution_context.operation_name == "RejectMe":
            self.execution_context.result = GraphQLExecutionResult(
                data=None,
                errors=[GraphQLError("Well you asked for it")],
            )


schema = strawberry.Schema(
    Query,
    extensions=[
        RejectSomeQueries,
    ],
)
```

</details>

<details>
  <summary>Operation Extensions</summary>

```python
import time
import strawberry
from strawberry.extensions import SchemaExtension


class QueryStatsExtension(SchemaExtension):
    def on_operation(self):
        execution_context = self.execution_context

        if execution_context.operation_extensions:
            if execution_context.operation_extensions.get("stats", False):
                start_time = time.time()
                yield
                end_time = time.time()
                self.execution_context.extensions_results["stats"] = {
                    "query_time": end_time - start_time
                }
                return

        yield


schema = strawberry.Schema(
    Query,
    extensions=[
        QueryStatsExtension,
    ],
)
```

</details>

### Execution Context

The `SchemaExtension` object has an `execution_context` property on `self` of
type `ExecutionContext`.

This object can be used to gain access to additional GraphQL context, or the
request context. Take a look at the
[`ExecutionContext` type](https://github.com/strawberry-graphql/strawberry/blob/main/strawberry/types/execution.py)
for available data.

```python
from strawberry.extensions import SchemaExtension

from mydb import get_db_session


class MyExtension(SchemaExtension):
    def on_operation(self):
        self.execution_context.context["db"] = get_db_session()
        yield
        self.execution_context.context["db"].close()
```

---

### Guides Dataloaders (`docs/guides/dataloaders.md`)

---
title: DataLoaders
---

# DataLoaders

Strawberry comes with a built-in DataLoader, a generic utility that can be used
to reduce the number of requests to databases or third party APIs by batching
and caching requests.

<Note>

DataLoaders provide an async API, so they only work in async context

</Note>

Refer the official DataLoaders
[specification](https://github.com/graphql/dataloader) for an advanced guide on
DataLoaders.

## Basic usage

Here's how you'd use a DataLoader, first we need to define a function that
allows to fetch data in batches. Let's say that we have a user type, that has
only an id:

```python
import strawberry


@strawberry.type
class User:
    id: strawberry.ID
```

we need to define a function that returns a list of users based on a list of
keys passed:

```python
from typing import List


async def load_users(keys: List[int]) -> List[User]:
    return [User(id=key) for key in keys]
```

Normally this function would interact with a database or 3rd party API, but for
our example we don't need that.

Now that we have a loader function, we can define a DataLoader and use it:

```python
from strawberry.dataloader import DataLoader

loader = DataLoader(load_fn=load_users)

user = await loader.load(1)
```

This will result in a call to `load_users` with keys equal to `[1]`. Where this
becomes really powerful is when you make multiple requests, like in this
example:

```python
import asyncio

[user_a, user_b] = await asyncio.gather(loader.load(1), loader.load(2))
```

This will result in a call to `load_users` with keys equal to `[1, 2]`. Thus
reducing the number of calls to our database or 3rd party services to 1.

Additionally by default DataLoader caches the loads, so for example the
following code:

```python
await loader.load(1)
await loader.load(1)
```

Will result in only one call to `load_users`.

And finally sometimes we'll want to load more than one key at a time. In those
cases we can use the `load_many` method.

```python
[user_a, user_b, user_c] = await loader.load_many([1, 2, 3])
```

### Errors

An error associated with a particular key can be indicated by including an
exception value in the corresponding position in the returned list. This
exception will be thrown by the `load` call for that key. With the same `User`
class from above:

```python
from typing import List, Union
from strawberry.dataloader import DataLoader

users_database = {
    1: User(id=1),
    2: User(id=2),
}


async def load_users(keys: List[int]) -> List[Union[User, ValueError]]:
    def lookup(key: int) -> Union[User, ValueError]:
        if user := users_database.get(key):
            return user

        return ValueError("not found")

    return [lookup(key) for key in keys]


loader = DataLoader(load_fn=load_users)
```

For this loader, calls like `await loader.load(1)` will return `User(id=1)`,
while `await loader.load(3)` will raise `ValueError("not found")`.

It's important that the `load_users` function returns exception values within
the list for each incorrect key. A call with `keys == [1, 3]` returns
`[User(id=1), ValueError("not found")]`, and doesn't raise the `ValueError`
directly. If the `load_users` function raises an exception, even `load`s with an
otherwise valid key, like `await loader.load(1)`, will raise that exception.

### Overriding Cache Key

By default, the input is used as cache key. In the above examples, the cache key
is always a scalar (int, float, string, etc.) and uniquely resolves the data for
the input.

In practical applications there are situations where it requires combination of
fields to uniquely identify the data. By providing `cache_key_fn` argument to
the `DataLoader` the behaviour of generating key is changed. It is also useful
when objects are keys and two objects should be considered equivalent. The
function definition takes an input parameter and returns a `Hashable` type.

```python
from typing import List, Union
from strawberry.dataloader import DataLoader


class User:
    def __init__(self, custom_id: int, name: str):
        self.id: int = custom_id
        self.name: str = name


async def loader_fn(keys):
    return keys


def custom_cache_key(key):
    return key.id


loader = DataLoader(load_fn=loader_fn, cache_key_fn=custom_cache_key)
data1 = await loader.load(User(1, "Nick"))
data2 = await loader.load(User(1, "Nick"))
assert data1 == data2  # returns true
```

`loader.load(User(1, "Nick"))` will call `custom_cache_key` internally, passing
the object as parameter to the function which will return `User.id` as key that
is `1`. The second call will check the cache for the key returned by
`custom_cache_key` and will return the cache object from the loader cache.

The implementation relies on users to handle conflicts while generating the
cache key. In case of conflict the data will be overriden for the key.

### Cache invalidation

By default DataLoaders use an internal cache. It is great for performance,
however it can cause problems when the data is modified (i.e., a mutation), as
the cached data is no longer be valid! 😮

To fix it, you can explicitly invalidate the data in the cache, using one of
these ways:

- Specifying a key with `loader.clear(id)`,
- Specifying several keys with `loader.clear_many([id1, id2, id3, ...])`,
- Invalidating the whole cache with `loader.clear_all()`

### Importing data into cache

While dataloaders are powerful and efficient, they do not support complex
queries.

If your app needs them, you'll probably mix dataloaders and direct database
calls.

In these scenarios, it is useful to import the data retrieved externally into
the dataloader, in order to avoid reloading data afterwards.

For example:

<CodeGrid>

```python
@strawberry.type
class Person:
    id: strawberry.ID
    friends_ids: strawberry.Private[List[strawberry.ID]]

    @strawberry.field
    async def friends(self) -> List[Person]:
        return await loader.load_many(self.friends_ids)


@strawberry.type
class Query:
    @strawberry.field
    async def get_all_people(self) -> List[Person]:
        # Fetch all people from the database, without going through the dataloader abstraction
        people = await database.get_all_people()

        # Insert the people we fetched in the dataloader cache
        # Since "all people" are now in the cache, accessing `Person.friends` will not
        # trigger any extra database access
        loader.prime_many({person.id: person for person in people})

        return people
```

```graphql
{
  getAllPeople {
    id
    friends {
      id
    }
  }
}
```

</CodeGrid>

### Custom Cache

DataLoader's default cache is per-request and it caches data in memory. This
strategy might not be optimal or safe for all use cases. For example, if you are
using DataLoader in a distributed environment, you might want to use a
distributed cache. DataLoader let you override the custom caching logic, which
can get data from other persistent caches (e.g Redis)

`DataLoader` provides an argument `cache_map`. It takes an instance of a class
which implements an abstract interface `AbstractCache`. The interface methods
are `get`, `set`, `delete` and `clear`

The `cache_map` parameter overrides the `cache_key_fn` if both arguments are
provided.

```python
from typing import List, Union, Any, Optional

import strawberry
from strawberry.asgi import GraphQL
from strawberry.dataloader import DataLoader, AbstractCache

from starlette.requests import Request
from starlette.websockets import WebSocket
from starlette.responses import Response


class UserCache(AbstractCache):
    def __init__(self):
        self.cache = {}

    def get(self, key: Any) -> Union[Any, None]:
        return self.cache.get(key)  # fetch data from persistent cache

    def set(self, key: Any, value: Any) -> None:
        self.cache[key] = value  # store data in the cache

    def delete(self, key: Any) -> None:
        del self.cache[key]  # delete key from the cache

    def clear(self) -> None:
        self.cache.clear()  # clear the cache


@strawberry.type
class User:
    id: strawberry.ID
    name: str


async def load_users(keys) -> List[User]:
    return [User(id=key, name="Jane Doe") for key in keys]


class MyGraphQL(GraphQL):
    async def get_context(
        self, request: Union[Request, WebSocket], response: Optional[Response]
    ) -> Any:
        return {"user_loader": DataLoader(load_fn=load_users, cache_map=UserCache())}


@strawberry.type
class Query:
    @strawberry.field
    async def get_user(self, info: strawberry.Info, id: strawberry.ID) -> User:
        return await info.context["user_loader"].load(id)


schema = strawberry.Schema(query=Query)
app = MyGraphQL(schema)
```

## Usage with GraphQL

Let's see an example of how you can use DataLoaders with GraphQL:

```python
from typing import List

from strawberry.dataloader import DataLoader
import strawberry


@strawberry.type
class User:
    id: strawberry.ID


async def load_users(keys) -> List[User]:
    return [User(id=key) for key in keys]


loader = DataLoader(load_fn=load_users)


@strawberry.type
class Query:
    @strawberry.field
    async def get_user(self, id: strawberry.ID) -> User:
        return await loader.load(id)


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

Here we have defined the same loader as before, along side with a GraphQL query
that allows to fetch a single user by id.

We can use this query by doing the following request:

<CodeGrid>

```graphql
{
  first: getUser(id: 1) {
    id
  }
  second: getUser(id: 2) {
    id
  }
}
```

```json
{
  "data": {
    "first": {
      "id": 1
    },
    "second": {
      "id": 2
    }
  }
}
```

</CodeGrid>

Even if this query is fetching two users, it still results in one call to
`load_users`.

## Usage with context

As you have seen in the code above, the dataloader is instantiated outside the
resolver, since we need to share it between multiple resolvers or even between
multiple resolver calls. However this is a not a recommended pattern when using
your schema inside a server because the dataloader will cache results for as
long as the server is running.

Instead a common pattern is to create the dataloader when creating the GraphQL
context so that it only caches results with a single request. Let's see an
example of this using our ASGI view:

```python
from typing import List, Union, Any, Optional

import strawberry
from strawberry.asgi import GraphQL
from strawberry.dataloader import DataLoader

from starlette.requests import Request
from starlette.websockets import WebSocket
from starlette.responses import Response


@strawberry.type
class User:
    id: strawberry.ID


async def load_users(keys) -> List[User]:
    return [User(id=key) for key in keys]


class MyGraphQL(GraphQL):
    async def get_context(
        self, request: Union[Request, WebSocket], response: Optional[Response]
    ) -> Any:
        return {"user_loader": DataLoader(load_fn=load_users)}


@strawberry.type
class Query:
    @strawberry.field
    async def get_user(self, info: strawberry.Info, id: strawberry.ID) -> User:
        return await info.context["user_loader"].load(id)


schema = strawberry.Schema(query=Query)
app = MyGraphQL(schema)
```

You can now run the example above with any ASGI server, you can read
[ASGI](../integrations/asgi.md)) to get more details on how to run the app. In
case you choose uvicorn you can install it wih

```shell
pip install uvicorn
```

and then, assuming we named our file above `schema.py` we start the app with

```shell
uvicorn schema:app
```

---

### Guides Errors (`docs/guides/errors.md`)

---
title: Dealing with errors
---

# Dealing with errors

There are multiple different types of errors in GraphQL and each can be handled
differently.

In this guide we will outline the different types of errors that you will
encounter when building a GraphQL server.

**Note**: By default Strawberry will log all execution errors to a
`strawberry.execution` logger:
[/docs/types/schema#handling-execution-errors](../types/schema#handling-execution-errors).

## GraphQL validation errors

GraphQL is strongly typed and so Strawberry validates all queries before
executing them. If a query is invalid it isn’t executed and instead the response
contains an `errors` list:

<CodeGrid>

```graphql
{
  hi
}
```

```json
{
  "data": null,
  "errors": [
    {
      "message": "Cannot query field 'hi' on type 'Query'.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": null
    }
  ]
}
```

</CodeGrid>

Each error has a message, line, column and path to help you identify what part
of the query caused the error.

The validation rules are part of the GraphQL specification and built into
Strawberry, so there’s not really a way to customize this behavior. You can
disable all validation by using the
[DisableValidation](../extensions/disable-validation) extension.

### Strawberry input coercion errors

When Strawberry cannot coerce a value provided for one of its built-in `Date`,
`DateTime`, `Time`, `Decimal`, or `UUID` scalars, for a OneOf input object, or
for a relay `GlobalID`, or when a `strawberry.Maybe` field or argument that
doesn't accept `null` gets one, it raises `StrawberryInputCoercionError`. This
exception lets server-side error handling distinguish these client input errors
without changing the serialized GraphQL response.

Some of these errors are raised while graphql-core coerces variables, or while
Strawberry converts field arguments, and are then wrapped in another
`GraphQLError`, so error handlers should also check `original_error`:

```python
from graphql import GraphQLError

from strawberry.exceptions import StrawberryInputCoercionError


def is_strawberry_input_error(error: GraphQLError) -> bool:
    return isinstance(error, StrawberryInputCoercionError) or isinstance(
        error.original_error, StrawberryInputCoercionError
    )
```

## GraphQL type errors

When a query is executed each field must resolve to the correct type. For
example non-null fields cannot return None.

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello() -> str:
        return None


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

<CodeGrid>

```graphql
{
  hello
}
```

```json
{
  "data": null,
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Query.hello.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": ["hello"]
    }
  ]
}
```

</CodeGrid>

Each error has a message, line, column and path to help you identify what part
of the query caused the error.

## Unhandled execution errors

Sometimes a resolver will throw an unexpected error due to a programming error
or an invalid assumption. When this happens Strawberry catches the error and
exposes it in the top level `errors` field in the response.

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type
class Query:
    @strawberry.field
    def user() -> User:
        raise Exception("Can't find user")


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

<CodeGrid>

```graphql
{
  user {
    name
  }
}
```

```json
{
  "data": null,
  "errors": [
    {
      "message": "Can't find user",
      "locations": [
        {
          "line": 2,
          "column": 2
        }
      ],
      "path": ["user"]
    }
  ]
}
```

</CodeGrid>

## Partial responses for failed resolvers

By default, GraphQL allows partial responses when a resolver fails. This means
that successfully resolved fields are still returned alongside errors. However,
this applies only when the erroneous field is defined as optional.

Consider the following example:

```python
from typing import Optional
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def successful_field(self) -> Optional[str]:
        return "This field works"

    @strawberry.field
    def error_field(self) -> Optional[str]:
        raise Exception("This field fails")


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

<CodeGrid>

```graphql
{
  successfulField
  errorField
}
```

```json
{
  "data": {
    "successfulField": "This field works",
    "errorField": null
  },
  "errors": [
    {
      "message": "This field fails",
      "locations": [{ "line": 3, "column": 3 }],
      "path": ["errorField"]
    }
  ]
}
```

</CodeGrid>

The response includes both successfully resolved data and error details,
demonstrating GraphQL's ability to return partial results.

## Expected errors

If an error is expected then it is often best to express it in the schema. This
allows the client to deal with the error in a robust way.

This could be achieved by making the field optional when there is a possibility
that the data won’t exist:

```python
from typing import Optional
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def get_user(self, id: str) -> Optional[User]:
        try:
            user = get_a_user_by_their_ID
            return user
        except UserDoesNotExist:
            return None
```

When the expected error is more complicated it’s a good pattern to instead
return a union of types that either represent an error or a success response.
This pattern is often adopted with mutations where it’s important to be able to
return more complicated error details to the client.

For example, say you have a `registerUser` mutation where you need to deal with
the possibility that a user tries to register with a username that already
exists. You might structure your mutation type like this:

```python
import strawberry

from typing import Annotated, Union


@strawberry.type
class RegisterUserSuccess:
    user: User


@strawberry.type
class UsernameAlreadyExistsError:
    username: str
    alternative_username: str


# Create a Union type to represent the 2 results from the mutation
Response = Annotated[
    Union[RegisterUserSuccess, UsernameAlreadyExistsError],
    strawberry.union("RegisterUserResponse"),
]


@strawberry.mutation
def register_user(username: str, password: str) -> Response:
    if username_already_exists(username):
        return UsernameAlreadyExistsError(
            username=username,
            alternative_username=generate_username_suggestion(username),
        )

    user = create_user(username, password)
    return RegisterUserSuccess(user=user)
```

Then your client can look at the `__typename` of the result to determine what to
do next:

```graphql
mutation RegisterUser($username: String!, $password: String!) {
  registerUser(username: $username, password: $password) {
    __typename
    ... on UsernameAlreadyExistsError {
      alternativeUsername
    }
    ... on RegisterUserSuccess {
      user {
        id
        username
      }
    }
  }
}
```

This approach allows you to express the possible error states in the schema and
so provide a robust interface for your client to account for all the potential
outcomes from a mutation.

### Mapping expected exceptions to union results

If your application or integration already raises a specific exception for an
expected failure, you can map that exception to one of the GraphQL error types
in the field's return union by passing `exception_handlers` to
`strawberry.Schema`.

```python
import strawberry
from strawberry.types import Info
from strawberry.types.field import StrawberryField


class UsernameAlreadyExists(Exception):
    def __init__(self, username: str):
        self.username = username


@strawberry.type
class RegisterUserSuccess:
    user: User


@strawberry.type
class UsernameAlreadyExistsError:
    username: str


class UsernameAlreadyExistsHandler(
    strawberry.ExceptionHandler[UsernameAlreadyExists, UsernameAlreadyExistsError]
):
    def handle(
        self,
        exception: UsernameAlreadyExists,
        *,
        field: StrawberryField,
        info: Info,
    ) -> UsernameAlreadyExistsError:
        return UsernameAlreadyExistsError(username=exception.username)


@strawberry.type
class Mutation:
    @strawberry.mutation
    def register_user(
        self, username: str, password: str
    ) -> RegisterUserSuccess | UsernameAlreadyExistsError:
        # create_user may raise UsernameAlreadyExists
        user = create_user(username, password)
        return RegisterUserSuccess(user=user)


schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    exception_handlers=[UsernameAlreadyExistsHandler()],
)
```

Strawberry only converts exceptions when both of these are true:

- the exception is an instance of the handler's declared exception type
- the field return type is a union, or nullable union, containing the handler's
  declared error type

The two type parameters — the exception type the handler receives and the
GraphQL error type it returns — are the single source of truth: they drive the
matching at runtime, and type checkers use them to verify the signature of
`handle` against the declared types.

To map several Python exception classes to the same GraphQL error type,
parameterize the handler with their union, e.g.
`strawberry.ExceptionHandler[ErrorA | ErrorB, MyErrorType]`.

If you prefer explicit class attributes — or you are not using a type checker —
the same handler can declare its types with `exception_type` and `error_type`
attributes instead of type parameters:

```python
class UsernameAlreadyExistsHandler(strawberry.ExceptionHandler):
    exception_type = UsernameAlreadyExists
    error_type = UsernameAlreadyExistsError

    def handle(self, exception, *, field, info):
        return UsernameAlreadyExistsError(username=exception.username)
```

With this style `exception_type` accepts a single exception type or a tuple of
them, and the attributes also cover types that are only known at runtime. You
can mix the styles — for example parameterize the exception and supply a
runtime-only `error_type` as an attribute — but declaring both a type parameter
and a conflicting attribute for the same slot raises a `TypeError` at schema
creation. Note that type checkers will not verify the signature of `handle` when
you use attributes.

Handlers cover exceptions raised by the resolver, during argument conversion,
and by field extensions (for example a permission or validation extension
wrapping the field). Argument conversion runs before the field-extension chain,
so a conversion error is mapped directly and bypasses the field extensions —
matching how conversion errors have always been raised before permissions run.
Field extensions may catch or transform resolver exceptions before the handler
sees the final exception leaving the extension chain.

If multiple handlers match, Strawberry uses the first matching handler from the
`exception_handlers` list. Handlers do not apply to subscription fields or to
list fields such as `list[Success | UsernameAlreadyExistsError]`.

A handler can decline an individual exception by returning `None` (or an
awaitable resolving to `None`). Declining re-raises the original exception, so
it propagates as a normal GraphQL error as if no handler had matched. This lets
`handle` act as a per-instance filter — match a broad exception type, but only
convert the instances you recognize:

```python
class ValidationErrorHandler(
    strawberry.ExceptionHandler[ValidationProblem, ValidationError]
):
    def handle(
        self,
        exception: ValidationProblem,
        *,
        field: StrawberryField,
        info: Info,
    ) -> ValidationError | None:
        if exception.is_user_facing:
            return ValidationError(message=str(exception))
        # Not one we want to expose — let it propagate as a normal error.
        return None
```

When the error type is generic, parameterize the handler with the concrete
instantiation that appears in the union (for example
`strawberry.ExceptionHandler[MyError, ValidationError[int]]`), rather than the
bare generic (`ValidationError`), so it matches the correct member of the union.

Converted exceptions are treated as expected GraphQL results. They are not added
to the response's top-level `errors` list and are not passed to
`Schema.process_errors`, so avoid using broad exception types such as
`Exception` unless every matching error is safe to expose as a typed result.

On a synchronously executed field, `handle` must return its result
synchronously. An `async` handler returns a coroutine, which fails the same way
an `async` resolver does on a sync field: `execute_sync` returns an
`ExecutionResult` whose `errors` contain a `GraphQLError` stating that execution
could not complete synchronously.

---

## Additional resources:

[A Guide to GraphQL Errors | productionreadygraphql.com](https://productionreadygraphql.com/2020-08-01-guide-to-graphql-errors/)

[200 OK! Error Handling in GraphQL | sachee.medium.com](https://sachee.medium.com/200-ok-error-handling-in-graphql-7ec869aec9bc)

---

### Guides Federation V1 (`docs/guides/federation-v1.md`)

---
title: Federation V1
---

<Warning>

This guide refers to Apollo Federation 1, if you're looking for the 2.0 guide,
please see the [federation v2](federation.md) guide.

You can also see the
[What's new in federation 2](https://www.apollographql.com/docs/federation/federation-2/new-in-federation-2/)
for more details.

</Warning>

# Apollo Federation V1 Guide

Apollo Federation allows you to combine multiple GraphQL APIs into one. This can
be extremely useful when working with a service oriented architecture.

Strawberry supports
[Apollo Federation](https://www.apollographql.com/docs/federation) out of the
box, that means that you can create services using Strawberry and federate them
via Apollo Gateway.

<Note>

We don’t have a gateway server, you’ll still need to use the Apollo Gateway for
this.

</Note>

## Federated schema example

Let’s look at an example on how to implement Apollo Federation using Strawberry.
Let's assume we have an application with two services that each expose a GraphQL
API:

1. `books`: a service to manage all the books we have
2. `reviews`: a service to manage book reviews

### Books service

Our `book` service might look something like this:

```python
@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    title: str


def get_all_books() -> List[Book]:
    return [Book(id=1, title="The Dark Tower")]


@strawberry.type
class Query:
    all_books: List[Book] = strawberry.field(resolver=get_all_books)


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

We defined two types: `Book` and `Query`, where `Query` has only one field that
allows us to fetch all the books.

Notice that the `Book` type is using the `strawberry.federation.type` decorator,
as opposed to the normal `strawberry.type`, this new decorator extends the base
one and allows us to define federation-specific attributes on the type.

Here, we are telling the federation system that the `Book`'s `id` field is its
uniquely-identifying key.

<Note>

Federation keys can be thought of as primary keys. They are used by the gateway
to query types between multiple services and then join them into the augmented
type.

</Note>

### Reviews service

Now, let’s take a look at our review service: we want to define a type for a
review but also extend the `Book` type to have a list of reviews.

```python
@strawberry.type
class Review:
    id: int
    body: str


def get_reviews(root: "Book") -> List[Review]:
    return [
        Review(id=id_, body=f"A review for {root.id}")
        for id_ in range(root.reviews_count)
    ]


@strawberry.federation.type(extend=True, keys=["id"])
class Book:
    id: strawberry.ID = strawberry.federation.field(external=True)
    reviews_count: int
    reviews: List[Review] = strawberry.field(resolver=get_reviews)

    @classmethod
    def resolve_reference(cls, id: strawberry.ID):
        # here we could fetch the book from the database
        # or even from an API
        return Book(id=id, reviews_count=3)
```

Now things are looking more interesting; the `Review` type is a GraphQL type
that holds the contents of the review.

We've also been able to extend the `Book` type by using again
`strawberry.federation.type`, this time passing `extend=True` as an argument.
This is important because we need to tell federation that we are extending a
type that already exists, not creating a new one.

We have also declared three fields on `Book`, one of which is `id` which is
marked as `external` with `strawberry.federation.field(external=True)`. This
tells federation that this field is not available in this service, and that it
comes from another service.

The other fields are `reviews` (the list of `Reviews` for this book) and
`reviews_count` (the number of reviews for this book).

Finally, we also have a class method, `resolve_reference`, that allows us to
instantiate types when they are referred to by other services. The
`resolve_reference` method is called when a GraphQL operation references an
entity across multiple services. For example, when making this query:

```graphql
{
  # query defined in the books service
  books {
    title
    # field defined in the reviews service
    reviews {
      body
    }
  }
}
```

`resolve_reference` is called with the `id` of the book for each book returned
by the books service. Recall that above we defined the `id` field as the `key`
for the `Book` type. In this example we are creating an instance of `Book` with
the requested `id` and a fixed number of reviews.

If we were to add more fields to `Book` that were stored in a database, this
would be where we could perform queries for these fields' values.

Now we need to do is to define a `Query` type, even if our service only has one
type that is not used directly in any GraphQL query. This is because the GraphQL
spec mandates that a GraphQL server defines a Query type, even if it ends up
being empty/unused. Finally we also need to let Strawberry know about our Book
and Review types. Since they are not reachable from the `Query` field itself,
Strawberry won't be able to find them by default.

```python
@strawberry.type
class Query:
    _hi: str = strawberry.field(resolver=lambda: "Hello world!")


schema = strawberry.federation.Schema(query=Query, types=[Book, Review])
```

## The gateway

Now we have our services up and running, we need to configure a gateway to
consume our services. Apollo Gateway is the official gateway server for Apollo
Federation. Here's an example on how to configure the gateway:

```js
const { ApolloServer } = require("apollo-server");
const { ApolloGateway } = require("@apollo/gateway");

const gateway = new ApolloGateway({
  serviceList: [
    { name: "books", url: "http://localhost:8000" },
    { name: "reviews", url: "http://localhost:8080" },
  ],
});

const server = new ApolloServer({ gateway });

server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});
```

When running this example you'll be able to run query like the following:

```graphql
{
  allBooks {
    id
    reviewsCount
    reviews {
      body
    }
  }
}
```

We have provided a full example that you can run and tweak to play with
Strawberry and Federation. The repo is available here:
[https://github.com/strawberry-graphql/federation-demo](https://github.com/strawberry-graphql/federation-demo)

---

### Guides Federation (`docs/guides/federation.md`)

---
title: Federation 2
---

# Apollo Federation 2 Guide

<Note>

This guide refers to Apollo Federation 2, if you're looking for the 1.0 guide,
please see the [federation v1](federation-v1.md) guide.

</Note>

Apollo Federation allows you to combine multiple GraphQL APIs into one. This can
be extremely useful when working with a service oriented architecture.

Strawberry supports
[Apollo Federation 2](https://www.apollographql.com/docs/federation/federation-2/new-in-federation-2/)
out of the box, that means that you can create services using Strawberry and
federate them via Apollo Gateway or Apollo Router.

<Warning>

Federated schemas expose federation-specific fields, including `_service`, so
gateways and routers can fetch the service SDL and compose the supergraph. The
[`DisableIntrospection`](../extensions/disable-introspection.md) extension
blocks standard GraphQL introspection fields such as `__schema` and `__type`,
but it does not block `_service { sdl }`.

If your federated service is reachable by untrusted clients, use authentication,
authorization, or network controls to restrict access to federation fields and
make sure entity resolvers enforce their own access checks.

</Warning>

## Federated schema example

Let’s look at an example on how to implement Apollo Federation using Strawberry.
Let's assume we have an application with two services that each expose a GraphQL
API:

1. `books`: a service to manage all the books we have
2. `reviews`: a service to manage book reviews

Our folder structure will look something like this:

```text
my-app/
├─ books/
│  ├─ app.py
├─ reviews/
│  ├─ app.py
```

<Note>

This guide assumes you've installed strawberry in both the books and reviews
service

</Note>

### Books service

Let's create the `books` service, copy the following inside `books/app.py`

```python
from typing import List

import strawberry


@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    title: str


def get_all_books() -> List[Book]:
    return [Book(id=strawberry.ID("1"), title="The Dark Tower")]


@strawberry.type
class Query:
    all_books: List[Book] = strawberry.field(resolver=get_all_books)


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

<Note>

Strawberry supports Apollo Federation 2 only. By default, schemas use Federation
version 2.11 (the latest supported version). You can specify a different version
if needed:

```python
schema = strawberry.federation.Schema(
    query=Query,
    federation_version="2.5",  # Specify a specific version if needed
)
```

Supported versions: 2.0 - 2.11

</Note>

We defined two types: `Book` and `Query`, where `Query` has only one field that
allows us to fetch all the books.

Notice that the `Book` type is using the `strawberry.federation.type` decorator,
as opposed to the normal `strawberry.type`, this new decorator extends the base
one and allows us to define federation-specific attributes on the type.

Here, we are telling the federation system that the `Book`'s `id` field is its
uniquely-identifying key.

<Note>

Federation keys can be thought of as primary keys. They are used by the gateway
to query types between multiple services and then join them into the augmented
type.

</Note>

### Reviews service

Now, let’s take a look at our review service: we want to define a type for a
review but also extend the `Book` type to have a list of reviews.

Copy the following inside `reviews/app.py`:

```python
from typing import List

import strawberry


@strawberry.type
class Review:
    id: int
    body: str


def get_reviews(root: "Book") -> List[Review]:
    return [
        Review(id=id_, body=f"A review for {root.id}")
        for id_ in range(root.reviews_count)
    ]


@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    reviews_count: int
    reviews: List[Review] = strawberry.field(resolver=get_reviews)

    @classmethod
    def resolve_reference(cls, id: strawberry.ID):
        # here we could fetch the book from the database
        # or even from an API
        return Book(id=id, reviews_count=3)


@strawberry.type
class Query:
    _hi: str = strawberry.field(resolver=lambda: "Hello World!")


schema = strawberry.federation.Schema(query=Query, types=[Book, Review])
```

Now things are looking more interesting; the `Review` type is a GraphQL type
that holds the contents of the review.

But we also have a `Book` which has 3 fields, `id`, `reviews_count` and
`reviews`.

<Note>

In Apollo Federation 1 we'd need to mark the `Book` type as an extension and
also we'd need to mark `id` as an external field, this is not the case in Apollo
Federation 2.

</Note>

Finally, we also have a class method, `resolve_reference`, that allows us to
instantiate types when they are referred to by other services. The
`resolve_reference` method is called when a GraphQL operation references an
entity across multiple services. For example, when making this query:

```graphql
{
  # query defined in the books service
  allBooks {
    title
    # field defined in the reviews service
    reviews {
      body
    }
  }
}
```

`resolve_reference` is called with the `id` of the book for each book returned
by the books service. Recall that above we defined the `id` field as the `key`
for the `Book` type. In this example we are creating an instance of `Book` with
the requested `id` and a fixed number of reviews.

If we were to add more fields to `Book` that were stored in a database, this
would be where we could perform queries for these fields' values.

We also defined a `Query` type that has a single field, `_hi`, which returns a
string. This is required because the GraphQL spec mandates that a GraphQL server
defines a Query type, even if it ends up being empty/unused.

Finally we also need to let Strawberry know about our Book and Review types.
Since they are not reachable from the `Query` field itself, Strawberry won't be
able to find them.

<Note>

If you don't need any custom logic for your resolve_reference, you can omit it
and Strawberry will automatically instanciate the type for you. For example, if
we had a `Book` type with only an `id` field, Strawberry would be able to
instanciate it for us based on the data returned by the gateway.

```python
@strawberry.federation.type(keys=["id"])
class Book:
    id: strawberry.ID
    reviews: List[Review] = strawberry.field(resolver=get_reviews)
```

</Note>

## Let's run our services

Before starting Apollo Router to compose our schemas we need to run the
services.

In two terminal windows, run the following commands:

```shell
cd books
strawberry dev --port 3500 app
```

```shell
cd reviews
strawberry dev --port 3000 app
```

## Apollo Router

Now we have our services up and running, we need to configure a gateway to
consume our services. Apollo provides a router that can be used for this.

Before continuing we'll need to install Apollo Router by following
[their installation guide](https://www.apollographql.com/docs/router/quickstart/)
and we'll need to
[install Apollo's CLI](https://www.apollographql.com/docs/rover/getting-started)
to compose the schema.

<Note>

Composing the schema means combining all our service's schemas into a single
schema. The composed schema will be used by the router to route requests to the
appropriate services.

</Note>

Create a file called `supergraph.yaml` with the following contents:

```yaml
federation_version: 2
subgraphs:
  reviews:
    routing_url: http://localhost:3000
    schema:
      subgraph_url: http://localhost:3000

  books:
    routing_url: http://localhost:3500
    schema:
      subgraph_url: http://localhost:3500
```

This file will be used by rover to compose the schema, which can be done with
the following command:

```shell
# Creates prod-schema.graphql or overwrites if it already exists
rover supergraph compose --config ./supergraph.yaml > supergraph-schema.graphql
```

Now that we have the composed schema, we can start the router.

```shell
./router --supergraph supergraph-schema.graphql
```

Now that router is running we can go to
[http://localhost:4000](http://localhost:4000) and try to run the following
query:

```graphql
{
  allBooks {
    id
    reviewsCount
    reviews {
      body
    }
  }
}
```

if everything went well we should get the following result:

```json
{
  "data": {
    "allBooks": [
      {
        "id": "1",
        "reviewsCount": 3,
        "reviews": [
          {
            "body": "A review for 1"
          },
          {
            "body": "A review for 1"
          },
          {
            "body": "A review for 1"
          }
        ]
      }
    ]
  }
}
```

We have provided a full example that you can run and tweak to play with
Strawberry and Federation. The repo is available here:
[https://github.com/strawberry-graphql/federation-demo](https://github.com/strawberry-graphql/federation-demo)

## Federated schema directives

Strawberry provides implementations for
[Apollo federation-specific GraphQL directives](https://www.apollographql.com/docs/federation/federated-types/federated-directives/)
up to federation spec v2.11.

Some of these directives may not be necessary to directly include in your code,
and are accessed through other means.

- `@interfaceObject` (for more details, see
  [Extending interfaces](https://strawberry.rocks/docs/federation/entity-interfaces))
- `@key` (for more details, see
  [Entities (Apollo Federation)](https://strawberry.rocks/docs/federation/entities))
- `@link` (is automatically be added to the schema when any other federated
  schema directive is used)

Other directives you may need to specifically include when relevant.

- `@composeDirective`
- `@external`
- `@inaccessible`
- `@override`
- `@provides`
- `@requires`
- `@shareable`
- `@tag`
- `@authenticated`
- `@requiresScopes`
- `@policy`

For example, adding the following directives:

```python
import strawberry
from strawberry.federation.schema_directives import Inaccessible, Shareable, Tag


@strawberry.type(directives=[Key(fields="id"), Tag(name="experimental")])
class Book:
    id: strawberry.ID


@strawberry.type(directives=[Shareable()])
class CommonType:
    foo: str
    woops: bool = strawberry.field(directives=[Inaccessible()])
```

Will result in the following GraphQL schema:

```graphql
schema
  @link(
    url: "https://specs.apollo.dev/federation/v2.11"
    import: ["@key", "@inaccessible", "@shareable", "@tag"]
  ) {
  query: Query
  mutation: Mutation
}

type Book @tag(name: "experimental") @key(fields: "id", resolveable: true) {
  id: ID!
}

type CommonType @shareable {
  foo: String!
}
```

## Additional resources

[Apollo Federation Quickstart](https://www.apollographql.com/docs/federation/quickstart/setup/)

---

### Guides Field Extensions (`docs/guides/field-extensions.md`)

---
title: Field extensions
---

# Field extensions

Field extensions are a great way to implement reusable logic such as permissions
or pagination outside your resolvers. They wrap the underlying resolver and are
able to modify the field and all arguments passed to the resolver.

<Note>

The following examples only cover sync execution. To use extensions in async
contexts, please have a look at
[Async Extensions and Resolvers](#async-extensions-and-resolvers)

</Note>

```python
import strawberry
from strawberry.extensions import FieldExtension


class UpperCaseExtension(FieldExtension):
    def resolve(
        self, next_: Callable[..., Any], source: Any, info: strawberry.Info, **kwargs
    ):
        result = next_(source, info, **kwargs)
        return str(result).upper()


@strawberry.type
class Query:
    @strawberry.field(extensions=[UpperCaseExtension()])
    def string(self) -> str:
        return "This is a test!!"
```

In this example, the `UpperCaseExtension` wraps the resolver of the `string`
field (`next`) and modifies the resulting string to be uppercase. The extension
will be called instead of the resolver and receives the resolver function as the
`next` argument. Therefore, it is important to not modify any arguments that are
passed to `next` in an incompatible way.

<CodeGrid>

```graphql
query {
  string
}
```

```json
{
  "string": "THIS IS A TEST!!"
}
```

</CodeGrid>

## Modifying the field

<Warning>

Most of the `StrawberryField` API is not stable and might change in the future
without warning. Stable features include: `StrawberryField.type`,
`StrawberryField.python_name`, and `StrawberryField.arguments`.

</Warning>

In some cases, the extended field needs to be compatible with the added
extension. `FieldExtension` provides an `apply(field: StrawberryField)` method
that can be overriden to modify the field. It is called during _Schema
Conversion_. In the following example, we use `apply` to add a directive to the
field:

```python
import time
import strawberry
from strawberry.extensions import FieldExtension
from strawberry.schema_directive import Location
from strawberry.types.field import StrawberryField


@strawberry.schema_directive(locations=[Location.FIELD_DEFINITION])
class Cached:
    time: int = 100


class CachingExtension(FieldExtension):
    def __init__(self, caching_time=100):
        self.caching_time = caching_time
        self.last_cached = 0.0
        self.cached_result = None

    def apply(self, field: StrawberryField) -> None:
        field.directives.append(Cached(time=self.caching_time))

    def resolve(
        self, next_: Callable[..., Any], source: Any, info: strawberry.Info, **kwargs
    ) -> Any:
        current_time = time.time()
        if self.last_cached + self.caching_time > current_time:
            return self.cached_result
        self.cached_result = next_(source, info, **kwargs)
        return self.cached_result
```

<CodeGrid>

```python
@strawberry.type
class Client:
    @strawberry.field(extensions=[CachingExtensions(caching_time=200)])
    def analyzed_hours(self, info) -> int:
        return do_expensive_computation()
```

```graphql
type Client {
    analyzedHours: Int! @Cached(time=200)
}
```

</CodeGrid>

## Combining multiple field extensions

When chaining multiple field extensions, the last extension in the list is
called first. Then, it calls the next extension until it reaches the resolver.
The return value of each extension is passed as an argument to the next
extension. This allows for creating a chain of field extensions that each
perform a specific transformation on the data being passed through them.

```python
@strawberry.field(extensions=[LowerCaseExtension(), UpperCaseExtension()])
def my_field():
    return "My Result"
```

<Tip>

**Order matters**: the last extension in the list will be executed first, while
the first extension in the list extension will be applied to the field first.
This enables cases like adding relay pagination in front of an extension that
modifies the field's type.

</Tip>

## Async Extensions and Resolvers

Field Extensions support async execution using the `resolve_async` method. A
field extension can either support `sync`, `async`, or both. The appropriate
resolve function will be automatically chosen based on the type of resolver and
other extensions.

Since sync-only extensions cannot await the result of an async resolver, they
are not compatible with async resolvers or extensions.

The other way around is possible: you can add an async-only extension to a sync
resolver, or wrap sync-only extensions with it. This is enabled by an automatic
use of the `SyncToAsyncExtension`. Note that after adding an async-only
extension, you cannot wrap it with a sync-only extension anymore.

<Tip>

To optimize the performance of your resolvers, it's recommended that you
implement both the `resolve` and `resolve_async` methods when using an extension
on both sync and async fields. While the `SyncToAsyncExtension` is convenient,
it may add unnecessary overhead to your sync resolvers, leading to slightly
decreased performance.

</Tip>

```python
import strawberry
from strawberry.extensions import FieldExtension


class UpperCaseExtension(FieldExtension):
    def resolve(
        self, next: Callable[..., Any], source: Any, info: strawberry.Info, **kwargs
    ):
        result = next(source, info, **kwargs)
        return str(result).upper()

    async def resolve_async(
        self,
        next: Callable[..., Awaitable[Any]],
        source: Any,
        info: strawberry.Info,
        **kwargs,
    ):
        result = await next(source, info, **kwargs)
        return str(result).upper()


@strawberry.type
class Query:
    @strawberry.field(extensions=[UpperCaseExtension()])
    async def string(self) -> str:
        return "This is a test!!"
```

---

### Guides File Upload (`docs/guides/file-upload.md`)

---
title: File Upload
---

# File Upload

All Strawberry integrations support multipart uploads as described in the
[GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec).
This includes support for uploading single files as well as lists of files.

## Security

Note that multipart file upload support is disabled by default in all
integrations. Before enabling multipart file upload support, make sure you
address the
[security implications outlined in the specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security).
Usually, this entails enabling CSRF protection in your server framework (e.g.,
the `CsrfViewMiddleware` middleware in Django).

To enable file upload support, pass `multipart_uploads_enabled=True` to your
integration's view class. Refer to the integration-specific documentation for
more details on how to do this.

## Upload Scalar

Uploads can be used in mutations via the `Upload` scalar. The type passed at
runtime depends on the integration:

| Integration                               | Type                                                                                                                                                  |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| [AIOHTTP](/docs/integrations/aiohttp)     | [`io.BytesIO`](https://docs.python.org/3/library/io.html#io.BytesIO)                                                                                  |
| [ASGI](/docs/integrations/asgi)           | [`starlette.datastructures.UploadFile`](https://www.starlette.io/requests/#request-files)                                                             |
| [Channels](/docs/integrations/channels)   | [`django.core.files.uploadedfile.UploadedFile`](https://docs.djangoproject.com/en/dev/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile) |
| [Django](/docs/integrations/django)       | [`django.core.files.uploadedfile.UploadedFile`](https://docs.djangoproject.com/en/dev/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile) |
| [FastAPI](/docs/integrations/fastapi)     | [`fastapi.UploadFile`](https://fastapi.tiangolo.com/tutorial/request-files/#file-parameters-with-uploadfile)                                          |
| [Flask](/docs/integrations/flask)         | [`werkzeug.datastructures.FileStorage`](https://werkzeug.palletsprojects.com/en/latest/datastructures/#werkzeug.datastructures.FileStorage)           |
| [Quart](/docs/integrations/quart)         | [`quart.datastructures.FileStorage`](https://github.com/pallets/quart/blob/main/src/quart/datastructures.py)                                          |
| [Sanic](/docs/integrations/sanic)         | [`sanic.request.File`](https://sanic.readthedocs.io/en/stable/sanic/api/core.html#sanic.request.File)                                                 |
| [Starlette](/docs/integrations/starlette) | [`starlette.datastructures.UploadFile`](https://www.starlette.io/requests/#request-files)                                                             |

In order to have the correct runtime type in resolver type annotations (which
also gives you proper type checking with mypy/pyright), you can set a scalar
override based on the integrations above. For example with Starlette:

```python
import strawberry
from starlette.datastructures import UploadFile
from strawberry.file_uploads import UploadDefinition

schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    scalar_overrides={UploadFile: UploadDefinition},
)
```

With this configuration, you can use the framework's upload type directly in
your resolvers:

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    async def read_file(self, file: UploadFile) -> str:
        return (await file.read()).decode("utf-8")
```

This gives you proper IDE autocomplete and type checking, since the type
annotation matches the actual runtime type.

## ASGI / FastAPI / Starlette

Since these integrations use asyncio for communication, the resolver _must_ be
async.

Additionally, these servers rely on the `python-multipart` package, which is not
included by Strawberry by default. It can be installed directly, or, for
convenience, it is included in extras: `strawberry-graphql[asgi]` (for
ASGI/Starlette) or `strawberry-graphql[fastapi]` (for FastAPI). For example:

- if using Pip, `pip install 'strawberry-graphql[fastapi]'`
- if using uv, `uv add 'strawberry-graphql[fastapi]'`
- if using Poetry,
  `strawberry-graphql = { version = "...", extras = ["fastapi"] }` in
  `pyproject.toml`.

Example:

```python
import typing
import strawberry
from strawberry.file_uploads import Upload


@strawberry.input
class FolderInput:
    files: typing.List[Upload]


@strawberry.type
class Mutation:
    @strawberry.mutation
    async def read_file(self, file: Upload) -> str:
        return (await file.read()).decode("utf-8")

    @strawberry.mutation
    async def read_files(self, files: typing.List[Upload]) -> typing.List[str]:
        contents = []
        for file in files:
            content = (await file.read()).decode("utf-8")
            contents.append(content)
        return contents

    @strawberry.mutation
    async def read_folder(self, folder: FolderInput) -> typing.List[str]:
        contents = []
        for file in folder.files:
            content = (await file.read()).decode("utf-8")
            contents.append(content)
        return contents
```

## Sanic / Flask / Django / Channels / AIOHTTP

Example:

```python
import typing
import strawberry
from strawberry.file_uploads import Upload


@strawberry.input
class FolderInput:
    files: typing.List[Upload]


@strawberry.type
class Mutation:
    @strawberry.mutation
    def read_file(self, file: Upload) -> str:
        return file.read().decode("utf-8")

    @strawberry.mutation
    def read_files(self, files: typing.List[Upload]) -> typing.List[str]:
        contents = []
        for file in files:
            content = file.read().decode("utf-8")
            contents.append(content)
        return contents

    @strawberry.mutation
    def read_folder(self, folder: FolderInput) -> typing.List[str]:
        contents = []
        for file in folder.files:
            contents.append(file.read().decode("utf-8"))
        return contents
```

## Sending file upload requests

The tricky part is sending the HTTP request from the client because it must
follow the GraphQL multipart request specifications mentioned above.

The `multipart/form-data` POST request's data must include:

- `operations` key for GraphQL request with query and variables
- `map` key with mapping some multipart-data to exact GraphQL variable
- and other keys for multipart-data which contains binary data of files

Assuming you have your schema up and running, here there are some requests
examples:

### Sending one file

```shell
curl localhost:8000/graphql \
  -F operations='{ "query": "mutation($file: Upload!){ readFile(file: $file) }", "variables": { "file": null } }' \
  -F map='{ "file": ["variables.file"] }' \
  -F file=@a.txt
```

### Sending a list of files

```shell
curl localhost:8000/graphql \
  -F operations='{ "query": "mutation($files: [Upload!]!) { readFiles(files: $files) }", "variables": { "files": [null, null] } }' \
  -F map='{"file1": ["variables.files.0"], "file2": ["variables.files.1"]}' \
  -F file1=@b.txt \
  -F file2=@c.txt
```

### Sending nested files

```shell
curl localhost:8000/graphql \
  -F operations='{ "query": "mutation($folder: FolderInput!) { readFolder(folder: $folder) }", "variables": {"folder": {"files": [null, null]}} }' \
  -F map='{"file1": ["variables.folder.files.0"], "file2": ["variables.folder.files.1"]}' \
  -F file1=@b.txt \
  -F file2=@c.txt
```

---

### Guides Permissions (`docs/guides/permissions.md`)

---
title: Permissions
---

# Permissions

Permissions can be managed using `Permission` classes. A `Permission` class
extends `BasePermission` and has a `has_permission` method. It can be added to a
field using the `permission_classes` keyword argument. A basic example looks
like this:

```python
import typing
import strawberry
from strawberry.permission import BasePermission


class IsAuthenticated(BasePermission):
    message = "User is not authenticated"

    # This method can also be async!
    def has_permission(
        self, source: typing.Any, info: strawberry.Info, **kwargs
    ) -> bool:
        return False


@strawberry.type
class Query:
    user: str = strawberry.field(permission_classes=[IsAuthenticated])
```

Your `has_permission` method should check if this request has permission to
access the field. Note that the `has_permission` method can also be
asynchronous.

If the `has_permission` method returns a truthy value then the field access will
go ahead. Otherwise, an error will be raised using the `message` class
attribute.

Take a look at our [Dealing with Errors Guide](/docs/guides/errors) for more
information on how errors are handled.

```json
{
  "data": null,
  "errors": [
    {
      "message": "User is not authenticated"
    }
  ]
}
```

## Accessing user information

Accessing the current user information to implement your permission checks
depends on the web framework you are using.

Most frameworks will have a `Request` object where you can either access the
current user directly or access headers/cookies/query parameters to authenticate
the user.

All the Strawberry integrations provide this Request object in the
`info.context` object that is accessible in every resolver and in the
`has_permission` function.

You can find more details about a specific framework integration under the
"Integrations" heading in the navigation.

In this example we are using `starlette` which uses the
[ASGI](/docs/integrations/asgi) integration:

```python
import typing
from myauth import authenticate_header, authenticate_query_param

from starlette.requests import Request
from starlette.websockets import WebSocket
from strawberry.permission import BasePermission


class IsAuthenticated(BasePermission):
    message = "User is not authenticated"

    def has_permission(
        self, source: typing.Any, info: strawberry.Info, **kwargs
    ) -> bool:
        request: typing.Union[Request, WebSocket] = info.context["request"]

        if "Authorization" in request.headers:
            return authenticate_header(request)

        if "auth" in request.query_params:
            return authenticate_query_params(request)

        return False
```

Here we retrieve the `request` object from the `context` provided by `info`.
This object will be either a `Request` or `Websocket` instance from `starlette`
(see: [Request docs](https://www.starlette.io/requests/) and
[Websocket docs](https://www.starlette.io/websockets/)).

In the next step we take either the `Authorization` header or the `auth` query
parameter out of the `request` object, depending on which is available. We then
pass those on to some authenticate methods we've implemented ourselves.

Beyond providing hooks, Authentication is not currently Strawberry's
responsibility. You should provide your own helpers to figure out if a request
has the permissions you expect.

_For more discussion on Authentication see_
_[Issue #830](https://github.com/strawberry-graphql/strawberry/issues/830)._

## Custom Error Extensions & classes

In addition to the message, permissions automatically add pre-defined error
extensions to the error, and can use a custom `GraphQLError` class. This can be
configured by modifying the `error_class` and `error_extensions` attributes on
the `BasePermission` class. Error extensions will be propagated to the response
as specified in the
[GraphQL spec](https://strawberry.rocks/docs/types/exceptions).

```python
import typing

from strawberry.permission import BasePermission

from your_business_logic import GQLNotImplementedError


class IsAuthenticated(BasePermission):
    message = "User is not authenticated"
    error_class = GQLNotImplementedError
    error_extensions = {"code": "UNAUTHORIZED"}

    def has_permission(
        self, source: typing.Any, info: strawberry.Info, **kwargs
    ) -> bool:
        return False
```

# Advanced Permissions

Internally, permissions in strawberry use the `PermissionsExtension` field
extension.

The following snippet

```python
import strawberry


@strawberry.type
class Query:
    user: str = strawberry.field(permission_classes=[IsAuthenticated])
```

is internally equivalent to

```python
import strawberry
from strawberry.permission import PermissionExtension


@strawberry.type
class Query:
    @strawberry.field(extensions=[PermissionExtension(permissions=[IsAuthenticated()])])
    def name(self) -> str:
        return "ABC"
```

Using the new `PermissionExtension` API, permissions support even more features:

## Silent errors

In some cases, it is practical to avoid throwing an error when the user has no
permission to access the field and instead return `None` or an empty list to the
client. To return `None` or `[]` instead of raising an error, the
`fail_silently ` keyword argument on `PermissionExtension` can be set to `True`:

<Warning>
  Note that this will only work if the field returns a type that is nullable or
  a list, e.g. `Optional[str]` or `List[str]`.
</Warning>

```python
import strawberry
from strawberry.permission import PermissionExtension, BasePermission
from typing import Optional


@strawberry.type
class Query:
    @strawberry.field(
        extensions=[
            PermissionExtension(permissions=[IsAuthenticated()], fail_silently=True)
        ]
    )
    def name(self) -> Optional[str]:
        return "ABC"
```

Please note than in many cases, defensive programming is a better approach than
using `fail_silently`. Clients will no longer be able to distinguish between a
permission error and an empty result. Before implementing `fail_silently`,
consider if it is possible to use alternative solutions like the `@skip` or
`@include` directives to dynamically exclude fields from the query for users
without permission. Check the GraphQL documentation for more information on
[directives](https://graphql.org/learn/queries/#directives).

## Customizable Error Handling

To customize the error handling, the `on_unauthorized` method on the
`BasePermission` class can be used. Further changes can be implemented by
subclassing the `PermissionExtension` class.

## Schema Directives

Permissions will automatically be added as schema directives to the schema. This
behavior can be altered by setting the `add_directives` to `False` on
`PermissionExtension`, or by setting the `_schema_directive` class attribute of
the permission class to a custom directive.

---

### Guides Query Batching (`docs/guides/query-batching.md`)

---
title: Query Batching
---

# Query Batching

Query batching is a feature in Strawberry GraphQL that allows clients to send
multiple queries, mutations, or a combination of both in a single HTTP request.
This can help optimize network usage and improve performance for applications
that make frequent GraphQL requests.

This document explains how to enable query batching, its configuration options,
and how to integrate it into your application with an example using FastAPI.

---

## Enabling Query Batching

To enable query batching in Strawberry, you need to configure the
`StrawberryConfig` when defining your GraphQL schema. The batching configuration
is provided as a typed dictionary. Batching is disabled by default, if no
configuration is provided.

### Basic Configuration

```python
from strawberry.schema.config import StrawberryConfig

config = StrawberryConfig(batching_config={"max_operations": 10})
```

### Configuring Maximum Operations

To set a limit on the number of operations in a batch request, use the
`max_operations` key:

```python
from strawberry.schema.config import StrawberryConfig

config = StrawberryConfig(batching_config={"max_operations": 5})
```

When batching is enabled, the server can handle a list of operations
(queries/mutations) in a single request and return a list of responses.

## Example Integration with FastAPI

Query Batching is supported on all Strawberry GraphQL framework integrations.
Below is an example of how to enable query batching in a FastAPI application:

```python
import strawberry
from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter
from strawberry.schema.config import StrawberryConfig


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(batching_config={"max_operations": 5}),
)

graphql_app = GraphQLRouter(schema)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

### Running the Application

1. Save the code in a file (e.g., `app.py`).
2. Start the FastAPI server:

```bash
uvicorn app:app --reload
```

3. The GraphQL endpoint will be available at `http://127.0.0.1:8000/graphql`.

### Testing Query Batching

You can test query batching by sending a single HTTP request with multiple
GraphQL operations. For example:

#### Request

```bash
curl -X POST -H "Content-Type: application/json" \
-d '[{"query": "{ hello }"}, {"query": "{ hello }"}]' \
http://127.0.0.1:8000/graphql
```

#### Response

```json
[{ "data": { "hello": "Hello World" } }, { "data": { "hello": "Hello World" } }]
```

### Error Handling

#### Batching Disabled

If batching is not enabled in the server configuration and a batch request is
sent, the server will respond with a 400 status code and an error message:

```text
Batching is not enabled
```

#### Too Many Operations

If the number of operations in a batch exceeds the `max_operations` limit, the
server will return a 400 status code and an error message:

```text
Too many operations
```

### Limitations

#### Multipart Subscriptions

Query batching does not support multipart subscriptions. Attempting to batch
such operations will result in a 400 error with a relevant message.

### Additional Notes

Query batching is particularly useful for clients that need to perform multiple
operations simultaneously, reducing the overhead of multiple HTTP requests.
Ensure your client library supports query batching before enabling it on the
server.

---

### Guides Relay (`docs/guides/relay.md`)

---
title: Relay
---

# Relay Guide

<Warning>

Until Strawberry 0.268.0 we used to have a `GlobalID` in the GraphQL schema,
that has been changed to `ID`.

</Warning>

## What is Relay?

The relay spec defines some interfaces that GraphQL servers can follow to allow
clients to interact with them in a more efficient way. The spec makes two core
assumptions about a GraphQL server:

1. It provides a mechanism for refetching an object
2. It provides a description of how to page through connections.

You can read more about the relay spec
[here](https://relay.dev/docs/guides/graphql-server-specification/).

### Relay implementation example

Suppose we have the following type:

```python
@strawberry.type
class Fruit:
    name: str
    weight: str
```

We want it to have a globally unique ID, a way to retrieve a paginated results
list of it and a way to refetch if if necessary. For that, we need to inherit it
from the `Node` interface, annotate its attribute that will be used for the `ID`
field with `relay.NodeID` and implement its `resolve_nodes` abstract method.

```python
import strawberry
from strawberry import relay


@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[int]
    name: str
    weight: float

    @classmethod
    def resolve_nodes(
        cls,
        *,
        info: strawberry.Info,
        node_ids: Iterable[str],
        required: bool = False,
    ):
        return [
            all_fruits[int(nid)] if required else all_fruits.get(nid)
            for nid in node_ids
        ]


# In this example, assume we have a dict mapping the fruits code to the Fruit
# object itself
all_fruits: Dict[int, Fruit]
```

Explaining what we did here:

- We annotated `code` using `relay.NodeID[int]`. This makes `code` a
  [Private](../types/private.md) type, which will not be exposed to the GraphQL
  API, and also tells the `Node` interface that it should use its value to
  generate its `id: ID!` for the `Fruit` type.

- We also implemented the `resolve_nodes` abstract method. This method is
  responsible for retrieving the `Fruit` instances given its `id`. Because
  `code` is our id, `node_ids` will be a list of codes as a string.

<Note>

The `ID` gets generated by getting the base64 encoded version of the string
`<TypeName>:<NodeID>`. In the example above, the `Fruit` with a code of `1`
would have its `ID` as `base64("Fruit:1")` = `RnJ1aXQ6MQ==`

</Note>

Now we can expose it in the schema for retrieval and pagination like:

```python
@strawberry.type
class Query:
    node: relay.Node = relay.node()

    @relay.connection(relay.ListConnection[Fruit])
    def fruits(self) -> Iterable[Fruit]:
        # This can be a database query, a generator, an async generator, etc
        return all_fruits.values()
```

This will generate a schema like this:

```graphql
interface Node {
  id: ID!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

type Fruit implements Node {
  id: ID!
  name: String!
  weight: Float!
}

type FruitEdge {
  cursor: String!
  node: Fruit!
}

type FruitConnection {
  pageInfo: PageInfo!
  edges: [FruitEdge!]!
}

type Query {
  node(id: ID!): Node!
  fruits(
    before: String = null
    after: String = null
    first: Int = null
    last: Int = null
  ): FruitConnection!
}
```

With only that we have a way to query `node` to retrieve any `Node` implemented
type in our schema (which includes our `Fruit` type), and also a way to retrieve
a list of fruits with pagination.

For example, to retrieve a single fruit given its unique ID:

```graphql
query {
  node(id: "<some id>") {
    id
    ... on Fruit {
      name
      weight
    }
  }
}
```

Or to retrieve the first 10 fruits available:

```graphql
query {
  fruits(first: 10) {
    pageInfo {
      firstCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      # node here is the Fruit type
      node {
        id
        name
        weight
      }
    }
  }
}
```

The connection resolver for `relay.ListConnection` should return one of those:

- `List[<NodeType>]`
- `Iterator[<NodeType>]`
- `Iterable[<NodeType>]`
- `AsyncIterator[<NodeType>]`
- `AsyncIterable[<NodeType>]`
- `Generator[<NodeType>, Any, Any]`
- `AsyncGenerator[<NodeType>, Any]`

### The node field

As demonstrated above, the `Node` field can be used to retrieve/refetch any
object in the schema that implements the `Node` interface.

It can be defined in the `Query` objects in 4 ways:

- `node: Node`: This will define a field that accepts a `ID!` and returns a
  `Node` instance. This is the most basic way to define it.
- `node: Optional[Node]`: The same as `Node`, but if the given object doesn't
  exist, it will return `null`.
- `node: List[Node]`: This will define a field that accepts `[ID!]!` and returns
  a list of `Node` instances. They can even be from different types.
- `node: List[Optional[Node]]`: The same as `List[Node]`, but the returned list
  can contain `null` values if the given objects don't exist.

### Max results for connections

The implementation of `relay.ListConnection` will limit the number of results to
the `relay_max_results` configuration in the
[schema's config](../types/schema-configurations.md) (which defaults to `100`).

That can also be configured on a per-field basis by passing `max_results` to the
`@connection` decorator. For example:

```python
@strawerry.type
class Query:
    fruits: ListConnection[Fruit] = relay.connection(max_results=10_000)
```

### Custom connection pagination

The default `relay.Connection` class doesn't implement any pagination logic, and
should be used as a base class to implement your own pagination logic. All you
need to do is implement the `resolve_connection` classmethod.

The integration provides `relay.ListConnection`, which implements a limit/offset
approach to paginate the results. This is a basic approach and might be enough
for most use cases.

<Note>

`relay.ListConnection` implementes the limit/offset by using slices. That means
that you can override what the slice does by customizing the `__getitem__`
method of the object returned by your nodes resolver.

For example, when working with `Django`, `resolve_nodes` can return a
`QuerySet`, meaning that the slice on it will translate to a `LIMIT`/`OFFSET` in
the SQL query, which will fetch only the data that is needed from the database.

Also note that if that object doesn't have a `__getitem__` attribute, it will
use `itertools.islice` to paginate it, meaning that when a generator is being
resolved it will only generate as much results as needed for the given
pagination, the worst case scenario being the last results needing to be
returned.

</Note>

Now, suppose we want to implement a custom cursor-based pagination for our
previous example. We can do something like this:

```
/* Detailed source-code truncated for AI context efficiency. */
```

In the example above we specialized the `FruitCustomPaginationConnection` by
inheriting it from `relay.Connection[Fruit]`. We could still keep it generic by
inheriting it from `relay.Connection[relay.NodeType]` and then specialize it
when defining the field, making it possible to use our custom pagination logic
with more than one type.

### Custom connection arguments

By default the connection will automatically insert some arguments for it to be
able to paginate the results. Those are:

- `before`: Returns the items in the list that come before the specified cursor
- `after`: Returns the items in the list that come after the " "specified cursor
- `first`: Returns the first n items from the list
- `last`: Returns the items in the list that come after the " "specified cursor

You can still define extra arguments to be used by your own resolver or custom
pagination logic. For example, suppose we want to return the pagination of all
fruits whose name starts with a given string. We could do that like this:

```python
@strawberry.type
class Query:
    @relay.connection(relay.ListConnection[Fruit])
    def fruits_with_filter(
        self,
        info: strawberry.Info,
        name_endswith: str,
    ) -> Iterable[Fruit]:
        for f in fruits.values():
            if f.name.endswith(name_endswith):
                yield f
```

This will generate a schema like this:

```graphql
type Query {
  fruitsWithFilter(
    nameEndswith: String!
    before: String = null
    after: String = null
    first: Int = null
    last: Int = null
  ): FruitConnection!
}
```

### Convert the node to its proper type when resolving the connection

The connection expects that the resolver will return a list of objects that is a
subclass of its `NodeType`. But there may be situations where you are resolving
something that needs to be converted to the proper type, like an ORM model.

In this case you can subclass the `relay.Connection`/`relay.ListConnection` and
provide a custom `resolve_node` method to it, which by default returns the node
as is. For example:

```python
import strawberry
from strawberry import relay

from db import models


@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[int]
    name: str
    weight: float


@strawberry.type
class FruitDBConnection(relay.ListConnection[Fruit]):
    @classmethod
    def resolve_node(cls, node: FruitDB, *, info: strawberry.Info, **kwargs) -> Fruit:
        return Fruit(
            code=node.code,
            name=node.name,
            weight=node.weight,
        )


@strawberry.type
class Query:
    @relay.connection(FruitDBConnection)
    def fruits_with_filter(
        self,
        info: strawberry.Info,
        name_endswith: str,
    ) -> Iterable[models.Fruit]:
        return models.Fruit.objects.filter(name__endswith=name_endswith)
```

The main advantage of this approach instead of converting it inside the custom
resolver is that the `Connection` will paginate the `QuerySet` first, which in
case of django will make sure that only the paginated results are fetched from
the database. After that, the `resolve_node` function will be called for each
result to retrieve the correct object for it.

We used django for this example, but the same applies to any other other similar
use case, like SQLAlchemy, etc.

### The GlobalID type

The `GlobalID` type is a special object that contains all the info necessary to
identify and retrieve a given object that implements the `Node` interface.

It can for example be useful in a mutation, to receive an object and retrieve it
in its resolver. For example:

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    async def update_fruit_weight(
        self,
        info: strawberry.Info,
        id: relay.GlobalID,
        weight: float,
    ) -> Fruit:
        # resolve_node will return an awaitable that returns the Fruit object
        fruit = await id.resolve_node(info, ensure_type=Fruit)
        fruit.weight = weight
        return fruit

    @strawberry.mutation
    def update_fruit_weight_sync(
        self,
        info: strawberry.Info,
        id: relay.GlobalID,
        weight: float,
    ) -> Fruit:
        # resolve_node will return the Fruit object
        fruit = id.resolve_node_sync(info, ensure_type=Fruit)
        fruit.weight = weight
        return fruit
```

In the example above, you can also access the type name directly with
`id.type_name`, the raw node ID with `id.id`, or even resolve the type itself
with `id.resolve_type(info)`.

---

### Guides Schema Export (`docs/guides/schema-export.md`)

---
title: Schema export
---

# Schema export

Sometimes IDE plugins and code generation tools require you to provide a GraphQL
schema definition.

Strawberry provides a command to export your schema definition. The exported
schema will be described in the GraphQL schema definition language (SDL).

To use the command line tools, you have to ensure Strawberry was installed with
`strawberry-graphql[cli]`.

You can export your schema using the following command:

```bash
strawberry export-schema package.module:schema
```

where `schema` is the name of a Strawberry schema symbol or a callable symbol
that returns a Strawberry schema and `package.module` is the qualified name of
the module containing the symbol. The symbol name defaults to `schema` if not
specified.

In order to store the exported schema in a file, pipes or redirection can be
utilized:

```bash
strawberry export-schema package.module:schema > schema.graphql
```

Alternatively, the `--output` option can be used:

```bash
strawberry export-schema package.module:schema --output schema.graphql
```

---

### Guides Server (`docs/guides/server.md`)

---
title: Builtin server
---

# Builtin server

Sometimes you need to quickly prototype an API and don’t really need to use a
framework like Flask or Django.

Strawberry’s built in server helps with this use case. It allows to quickly have
a development server by running the following command:

```shell
strawberry dev package.module:schema
```

where `schema` is the name of a Strawberry schema symbol and `package.module` is
the qualified name of the module containing the symbol. The symbol name defaults
to `schema` if not specified.

When running that command you should be able to see a GraphiQL playground at
this url [http://localhost:8000/graphql](http://localhost:8000/graphql).

## Automatic reloading

Strawberry's built in server automatically reloads when changes to the module
containing the `schema` are detected. This way you can spend more time
prototyping your API rather than restarting development servers.

---

### Guides Tools (`docs/guides/tools.md`)

---
title: Tools
---

# Tools

Strawberry provides some utility functions to help you build your GraphQL
server. All tools can be imported from `strawberry.tools`

---

### `create_type`

Create a Strawberry type from a list of fields.

```python
def create_type(
    name: str,
    fields: List[StrawberryField],
    is_input: bool = False,
    is_interface: bool = False,
    description: Optional[str] = None,
    directives: Optional[Sequence[object]] = (),
    extend: bool = False,
) -> Type: ...
```

Example:

<CodeGrid>

```python
import strawberry
from strawberry.tools import create_type


@strawberry.field
def hello(info) -> str:
    return "World"


def get_name(info) -> str:
    return info.context.user.name


my_name = strawberry.field(name="myName", resolver=get_name)

Query = create_type("Query", [hello, my_name])

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

```graphql
type Query {
  hello: String!
  myName: String!
}
```

</CodeGrid>

---

### `merge_types`

Merge multiple Strawberry types into one. Example:

<CodeGrid>

```python
import strawberry
from strawberry.tools import merge_types


@strawberry.type
class QueryA:
    @strawberry.field
    def perform_a(self) -> str: ...


@strawberry.type
class QueryB:
    @strawberry.field
    def perform_b(self) -> str: ...


ComboQuery = merge_types("ComboQuery", (QueryB, QueryA))
```

```graphql
type ComboQuery {
  performB: String!
  performA: String!
}
```

</CodeGrid>

---

### Integrations Aiohttp (`docs/integrations/aiohttp.md`)

---
title: AIOHTTP
---

# AIOHTTP

Strawberry comes with a basic AIOHTTP integration. It provides a view that you
can use to serve your GraphQL schema:

```python
import strawberry
import asyncio
from aiohttp import web
from strawberry.aiohttp.views import GraphQLView
from typing import AsyncGenerator


@strawberry.type
class Query:
    @strawberry.field
    def hello(self, name: str = "World") -> str:
        return f"Hello, {name}!"


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def count(self, to: int = 100) -> AsyncGenerator[int, None]:
        for i in range(to):
            yield i
            await asyncio.sleep(1)


schema = strawberry.Schema(query=Query, subscription=Subscription)

app = web.Application()
app.router.add_route("*", "/graphql", GraphQLView(schema=schema))

web.run_app(app)
```

## Options

The `GraphQLView` accepts the following options at the moment:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

## Extending the view

The base `GraphQLView` class can be extended by overriding any of the following
methods:

- `async def get_context(self, request: Request, response: Union[Response, WebSocketResponse]) -> Context`
- `async def get_root_value(self, request: Request) -> Optional[RootValue]`
- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: Request) -> Response`
- `async def on_ws_connect(self, context: Context) -> Union[UnsetType, None, Dict[str, object]]`

### get_context

By overriding `GraphQLView.get_context` you can provide a custom context object
for your resolvers. You can return anything here; by default GraphQLView returns
a dictionary with the request.

```python
import strawberry
from typing import Union
from strawberry.types import Info
from strawberry.aiohttp.views import GraphQLView
from aiohttp.web import Request, Response, WebSocketResponse


class MyGraphQLView(GraphQLView):
    async def get_context(
        self, request: Request, response: Union[Response, WebSocketResponse]
    ):
        return {"request": request, "response": response, "example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called `"example"`.

Then we can use the context in a resolver. In this case the resolver will return
`1`.

### get_root_value

By overriding `GraphQLView.get_root_value` you can provide a custom root value
for your schema. This is probably not used a lot but it might be useful in
certain situations.

Here's an example:

```python
import strawberry
from aiohttp.web import Request
from strawberry.aiohttp.views import GraphQLView


class MyGraphQLView(GraphQLView):
    async def get_root_value(self, request: Request):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we configure a Query where requesting the `name` field will return
`"Patrick"` through the custom root value.

### process_result

By overriding `GraphQLView.process_result` you can customize and/or process
results before they are sent to a client. This can be useful for logging errors,
or even hiding them (for example to hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the request
and execution result.

```python
from aiohttp.web import Request
from strawberry.aiohttp.views import GraphQLView
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult


class MyGraphQLView(GraphQLView):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP and WebSocket JSON
requests. By default we use `json.loads` but you can override this method to use
a different decoder.

```python
from strawberry.aiohttp.views import GraphQLView
from typing import Union
import orjson


class MyGraphQLView(GraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.aiohttp.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from aiohttp.web import Request, Response
from strawberry.aiohttp.views import GraphQLView


class MyGraphQLView(GraphQLView):
    async def render_graphql_ide(self, request: Request) -> Response:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return Response(text=custom_html, content_type="text/html")
```

### on_ws_connect

By overriding `on_ws_connect` you can customize the behavior when a `graphql-ws`
or `graphql-transport-ws` connection is established. This is particularly useful
for authentication and authorization. By default, all connections are accepted.

To manually accept a connection, return `strawberry.UNSET` or a connection
acknowledgment payload. The acknowledgment payload will be sent to the client.

Note that the legacy protocol does not support `None`/`null` acknowledgment
payloads, while the new protocol does. Our implementation will treat
`None`/`null` payloads the same as `strawberry.UNSET` in the context of the
legacy protocol.

To reject a connection, raise a `ConnectionRejectionError`. You can optionally
provide a custom error payload that will be sent to the client when the legacy
GraphQL over WebSocket protocol is used.

```python
from typing import Dict
from strawberry.exceptions import ConnectionRejectionError
from strawberry.aiohttp.views import GraphQLView


class MyGraphQLView(GraphQLView):
    async def on_ws_connect(self, context: Dict[str, object]):
        connection_params = context["connection_params"]

        if not isinstance(connection_params, dict):
            # Reject without a custom graphql-ws error payload
            raise ConnectionRejectionError()

        if connection_params.get("password") != "secret":
            # Reject with a custom graphql-ws error payload
            raise ConnectionRejectionError({"reason": "Invalid password"})

        if username := connection_params.get("username"):
            # Accept with a custom acknowledgment payload
            return {"message": f"Hello, {username}!"}

        # Accept without a acknowledgment payload
        return await super().on_ws_connect(context)
```

---

### Integrations Asgi (`docs/integrations/asgi.md`)

---
title: ASGI
---

# ASGI

Strawberry comes with a basic ASGI integration. It provides an app that you can
use to serve your GraphQL schema. Before using Strawberry's ASGI support make
sure you install all the required dependencies by running:

```shell
pip install 'strawberry-graphql[asgi]'
```

Once that's done you can use Strawberry with ASGI like so:

```python
# server.py
from strawberry.asgi import GraphQL

from api.schema import schema

app = GraphQL(schema)
```

Every ASGI server will accept this `app` instance to start the server. For
example if you're using [uvicorn](https://pypi.org/project/uvicorn/) you run the
app with `uvicorn server:app`

## Options

The `GraphQL` app accepts the following options at the moment:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

## Extending the view

The base `GraphQL` class can be extended by overriding any of the following
methods:

- `async def get_context(self, request: Union[Request, WebSocket], response: Union[Response, WebSocket]) -> Context`
- `async def get_root_value(self, request: Union[Request, WebSocket]) -> Optional[RootValue]`
- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: Request) -> Response`
- `async def on_ws_connect(self, context: Context) -> Union[UnsetType, None, Dict[str, object]]`

### get_context

`get_context` allows to provide a custom context object that can be used in your
resolver. You can return anything here, by default we return a dictionary with
the request and the response.

```python
import strawberry
from typing import Union
from strawberry.asgi import GraphQL
from starlette.requests import Request
from starlette.responses import Response


class MyGraphQL(GraphQL):
    async def get_context(
        self, request: Union[Request, WebSocket], response: Optional[Response] = None
    ):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called "example".

Then we use the context in a resolver, the resolver will return "1" in this
case.

#### Setting response headers

It is possible to use `get_context` to set response headers. A common use case
might be cookie-based user authentication, where your login mutation resolver
needs to set a cookie on the response.

This is possible by updating the response object contained inside the context of
the `Info` object.

```python
import strawberry


@strawberry.type
class Mutation:
    @strawberry.mutation
    def login(self, info: strawberry.Info) -> bool:
        token = do_login()
        info.context["response"].set_cookie(key="token", value=token)
        return True
```

#### Setting background tasks

Similarly, [background tasks](https://www.starlette.io/background/) can be set
on the response via the context:

```python
import strawberry
from starlette.background import BackgroundTask


async def notify_new_flavour(name: str): ...


@strawberry.type
class Mutation:
    @strawberry.mutation
    def create_flavour(self, name: str, info: strawberry.Info) -> bool:
        info.context["response"].background = BackgroundTask(notify_new_flavour, name)
```

### get_root_value

`get_root_value` allows to provide a custom root value for your schema, this is
probably not used a lot but it might be useful in certain situations.

Here's an example:

```python
import strawberry
from typing import Union
from strawberry.asgi import GraphQL
from starlette.requests import Request
from starlette.websockets import WebSocket


class MyGraphQL(GraphQL):
    async def get_root_value(self, request: Union[Request, WebSocket]):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we are returning a Query where the name is "Patrick", so we when requesting
the field name we'll return "Patrick" in this case.

### process_result

`process_result` allows to customize and/or process results before they are sent
to the clients. This can be useful logging errors or hiding them (for example to
hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the request
and the execution results.

```python
from strawberry.asgi import GraphQL
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult
from starlette.requests import Request


class MyGraphQL(GraphQL):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP JSON requests. By default
we use `json.loads` but you can override this method to use a different decoder.

```python
from strawberry.asgi import GraphQL
from typing import Union
import orjson


class MyGraphQLView(GraphQL):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.asgi import GraphQL


class MyGraphQLView(GraphQL):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.asgi import GraphQL
from starlette.responses import HTMLResponse, Response


class MyGraphQL(GraphQL):
    async def render_graphql_ide(self, request: Request) -> Response:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return HTMLResponse(custom_html)
```

### on_ws_connect

By overriding `on_ws_connect` you can customize the behavior when a `graphql-ws`
or `graphql-transport-ws` connection is established. This is particularly useful
for authentication and authorization. By default, all connections are accepted.

To manually accept a connection, return `strawberry.UNSET` or a connection
acknowledgment payload. The acknowledgment payload will be sent to the client.

Note that the legacy protocol does not support `None`/`null` acknowledgment
payloads, while the new protocol does. Our implementation will treat
`None`/`null` payloads the same as `strawberry.UNSET` in the context of the
legacy protocol.

To reject a connection, raise a `ConnectionRejectionError`. You can optionally
provide a custom error payload that will be sent to the client when the legacy
GraphQL over WebSocket protocol is used.

```python
from typing import Dict
from strawberry.exceptions import ConnectionRejectionError
from strawberry.asgi import GraphQL


class MyGraphQL(GraphQL):
    async def on_ws_connect(self, context: Dict[str, object]):
        connection_params = context["connection_params"]

        if not isinstance(connection_params, dict):
            # Reject without a custom graphql-ws error payload
            raise ConnectionRejectionError()

        if connection_params.get("password") != "secret":
            # Reject with a custom graphql-ws error payload
            raise ConnectionRejectionError({"reason": "Invalid password"})

        if username := connection_params.get("username"):
            # Accept with a custom acknowledgment payload
            return {"message": f"Hello, {username}!"}

        # Accept without a acknowledgment payload
        return await super().on_ws_connect(context)
```

---

### Integrations Chalice (`docs/integrations/chalice.md`)

---
title: Chalice
---

# Chalice

Strawberry comes with an AWS Chalice integration. It provides a view that you
can use to serve your GraphQL schema:

Use the Chalice CLI to create a new project

```shell
chalice new-project badger-project
cd badger-project
```

Replace the contents of app.py with the following:

```python
from chalice import Chalice
from chalice.app import Request, Response

import strawberry
from strawberry.chalice.views import GraphQLView

app = Chalice(app_name="BadgerProject")


@strawberry.type
class Query:
    @strawberry.field
    def greetings(self) -> str:
        return "hello from the illustrious stack badger"


@strawberry.type
class Mutation:
    @strawberry.mutation
    def echo(self, string_to_echo: str) -> str:
        return string_to_echo


schema = strawberry.Schema(query=Query, mutation=Mutation)
view = GraphQLView(schema=schema)


@app.route("/graphql", methods=["GET", "POST"], content_types=["application/json"])
def handle_graphql() -> Response:
    request: Request = app.current_request
    result = view.execute_request(request)
    return result
```

And then run `chalice local` to start the localhost

```shell
chalice local
```

The GraphiQL interface can then be opened in your browser on
http://localhost:8000/graphql

## Options

The `GraphQLView` accepts two options at the moment:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphiql`: optional, defaults to `True`, whether to enable the GraphiQL
  interface.

## Extending the view

The base `GraphQLView` class can be extended by overriding any of the following
methods:

- `def get_context(self, request: Request, response: TemporalResponse) -> Context`
- `def get_root_value(self, request: Request) -> Optional[RootValue]`
- `def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `def render_graphql_ide(self, request: Request) -> Response`

### get_context

`get_context` allows to provide a custom context object that can be used in your
resolver. You can return anything here, by default we return a dictionary with
the request. By default; the `Response` object from `flask` is injected via the
parameters.

```python
import strawberry
from strawberry.chalice.views import GraphQLView
from strawberry.http.temporal import TemporalResponse
from chalice.app import Request


class MyGraphQLView(GraphQLView):
    def get_context(self, request: Request, response: TemporalResponse):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called "example".

Then we use the context in a resolver, the resolver will return "1" in this
case.

### get_root_value

`get_root_value` allows to provide a custom root value for your schema, this is
probably not used a lot but it might be useful in certain situations.

Here's an example:

```python
import strawberry
from strawberry.chalice.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def get_root_value(self):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we are returning a Query where the name is "Patrick", so we when requesting
the field name we'll return "Patrick" in this case.

### process_result

`process_result` allows to customize and/or process results before they are sent
to the clients. This can be useful logging errors or hiding them (for example to
hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the execution
result.

```python
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult
from strawberry.chalice.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def process_result(self, result: ExecutionResult) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP JSON requests. By default
we use `json.loads` but you can override this method to use a different decoder.

```python
from strawberry.chalice.views import GraphQLView
from typing import Union
import orjson


class MyGraphQLView(GraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.chalice.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.chalice.views import GraphQLView
from chalice.app import Request, Response


class MyGraphQLView(GraphQLView):
    def render_graphql_ide(self, request: Request) -> Response:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return Response(custom_html, headers={"Content-Type": "text/html"})
```

---

### Integrations Channels (`docs/integrations/channels.md`)

---
title: Channels
---

# Channels

Strawberry provides support for [Channels](https://channels.readthedocs.io/)
with
[Consumers](https://channels.readthedocs.io/en/stable/topics/consumers.html) to
provide GraphQL support over WebSockets and HTTP.

## Introduction

While Channels does require Django to be installed as a dependency, you can
actually run this integration without using Django's request handler. However,
the most common use case will be to run a normal Django project with GraphQL
subscriptions support, typically taking advantage of the Channel Layers
functionality which is exposed through the Strawberry integration.

---

## Getting Started

### Pre-requisites

Make sure you have read the following Channels documentation:

- [Introduction](https://channels.readthedocs.io/en/stable/introduction.html#)
- [Tutorial](https://channels.readthedocs.io/en/stable/tutorial/index.html)
- [Consumers](https://channels.readthedocs.io/en/stable/topics/consumers.html)
- And our [Subscriptions](../general/subscriptions) documentation.

If you have read the Channels documentation, You should know by now that:

1. ASGI application is a callable that can handle multiple send / receive
   operations without the need of a new application instance.
2. Channels is all about making ASGI applications instances (whether in another
   processes or in another machine) talk to each other seamlessly.
3. A `scope` is a single connection represented by a dict, whether it would be a
   websocket or an HTTP request or another protocol.
4. A `Consumer` is an ASGI application abstraction that helps to handle a single
   scope.

### Installation

Before using Strawberry's Channels support, make sure you install all the
required dependencies by running:

```shell
pip install 'strawberry-graphql[channels]'
```

---

## Tutorial

_The following example will pick up where the Channels tutorials left off._

By the end of this tutorial, You will have a graphql chat subscription that will
be able to talk with the channels chat consumer from the tutorial.

### Types setup

First, let's create some Strawberry-types for the chat.

```python
# mysite/gqlchat/subscription.py

import strawberry


@strawberry.input
class ChatRoom:
    room_name: str


@strawberry.type
class ChatRoomMessage:
    room_name: str
    current_user: str
    message: str
```

### Channel Layers

The Context for Channels integration includes the consumer, which has an
instance of the channel layer and the consumer's channel name. This tutorial is
an example of how this can be used in the schema to provide subscriptions to
events generated by background tasks or the web server. Even if these are
executed in other threads, processes, or even other servers, if you are using a
Layer backend like Redis or RabbitMQ you should receive the events.

To set this up, you'll need to make sure Channel Layers is configured as per the
[documentation](https://channels.readthedocs.io/en/stable/topics/channel_layers.html).

Then you'll want to add a subscription that accesses the channel layer and joins
one or more broadcast groups.

Since listening for events and passing them along to the client is a common use
case, the base consumer provides a high level API for that using a generator
pattern, as we will see below.

### The chat subscription

Now we will create the chat [subscription](../general/subscriptions.md).

```python
# mysite/gqlchat/subscription.py

import os
import threading

from typing import AsyncGenerator, List


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def join_chat_rooms(
        self,
        info: strawberry.Info,
        rooms: List[ChatRoom],
        user: str,
    ) -> AsyncGenerator[ChatRoomMessage, None]:
        """Join and subscribe to message sent to the given rooms."""
        ws = info.context["ws"]
        channel_layer = ws.channel_layer

        room_ids = [f"chat_{room.room_name}" for room in rooms]

        for room in room_ids:
            # Join room group
            await channel_layer.group_add(room, ws.channel_name)

        for room in room_ids:
            await channel_layer.group_send(
                room,
                {
                    "type": "chat.message",
                    "room_id": room,
                    "message": f"process: {os.getpid()} thread: {threading.current_thread().name}"
                    f" -> Hello my name is {user}!",
                },
            )

        async with ws.listen_to_channel("chat.message", groups=room_ids) as cm:
            async for message in cm:
                if message["room_id"] in room_ids:
                    yield ChatRoomMessage(
                        room_name=message["room_id"],
                        message=message["message"],
                        current_user=user,
                    )
```

Explanation: `Info.context["ws"]` or `Info.context["request"]` is a pointer to
the [`ChannelsConsumer`](#channelsconsumer) instance. Here we have first sent a
message to all the channel_layer groups (specified in the subscription argument
`rooms`) that we have joined the chat.

<Note>

The `ChannelsConsumer` instance is shared between all subscriptions created in a
single websocket connection. The `ws.listen_to_channel` context manager will
return a function to yield all messages sent using the given message `type`
(`chat.message` in the above example) but does not ensure that the message was
sent to the same group or groups that it was called with - if another
subscription using the same `ChannelsConsumer` also uses `ws.listen_to_channel`
with some other group names, those will be returned as well.

In the example we ensure `message["room_id"] in room_ids` before passing
messages on to the subscription client to ensure subscriptions only receive
messages for the chat rooms requested in that subscription.

</Note>

<Note>

We do not need to call `await channel_layer.group_add(room, ws.channel_name)` if
we don't want to send an initial message while instantiating the subscription.
It is handled by `ws.listen_to_channel`.

</Note>

### Chat message mutation

If you noticed, the subscription client can't send a message willingly. You will
have to create a mutation for sending messages via the `channel_layer`

```python
# mysite/gqlchat/subscription.py

from channels.layers import get_channel_layer


@strawberry.type
class Mutation:
    @strawberry.mutation
    async def send_chat_message(
        self,
        info: strawberry.Info,
        room: ChatRoom,
        message: str,
    ) -> None:
        channel_layer = get_channel_layer()

        await channel_layer.group_send(
            f"chat_{room.room_name}",
            {
                "type": "chat.message",
                "room_id": f"chat_{room.room_name}",
                "message": message,
            },
        )
```

### Creating the consumers

All we did so far is useless without creating an asgi consumer for our schema.
The easiest way to do that is to use the
[`GraphQLProtocolTypeRouter`](#graphqlprotocoltyperouter) which will wrap your
Django application, and route **HTTP and websockets** for `"/graphql"` to
Strawberry, while sending all other requests to Django. You'll need to modify
the `myproject.asgi.py` file from the Channels instructions to look something
like this:

```python
import os

from django.core.asgi import get_asgi_application
from strawberry.channels import GraphQLProtocolTypeRouter

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django_asgi_app = get_asgi_application()

# Import your Strawberry schema after creating the django ASGI application
# This ensures django.setup() has been called before any ORM models are imported
# for the schema.
from mysite.graphql import schema

application = GraphQLProtocolTypeRouter(
    schema,
    django_application=django_asgi_app,
)
```

This approach is not very flexible, taking away some useful capabilities of
Channels. For more complex deployments, i.e you want to integrate several ASGI
applications on different URLs and protocols, like what is described in the
[Channels documentation](https://channels.readthedocs.io/en/stable/topics/protocols.html).
You will probably craft your own
[`ProtocolTypeRouter`](https://channels.readthedocs.io/en/stable/topics/routing.html#protocoltyperouter).

An example of this (continuing from channels tutorial) would be:

```python
import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from django.urls import re_path
from strawberry.channels import GraphQLHTTPConsumer, GraphQLWSConsumer

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "berry.settings")
django_asgi_app = get_asgi_application()

# Import your Strawberry schema after creating the django ASGI application
# This ensures django.setup() has been called before any ORM models are imported
# for the schema.

from chat import routing
from mysite.graphql import schema

gql_http_consumer = AuthMiddlewareStack(GraphQLHTTPConsumer.as_asgi(schema=schema))
gql_ws_consumer = GraphQLWSConsumer.as_asgi(schema=schema)

websocket_urlpatterns = routing.websocket_urlpatterns + [
    re_path(r"graphql", gql_ws_consumer),
]

application = ProtocolTypeRouter(
    {
        "http": URLRouter(
            [
                re_path("^graphql", gql_http_consumer),
                re_path(
                    "^", django_asgi_app
                ),  # This might be another endpoint in your app
            ]
        ),
        "websocket": AuthMiddlewareStack(URLRouter(websocket_urlpatterns)),
    }
)
```

This example demonstrates some ways that Channels can be set up to handle
routing. A very common scenario will be that you want user and session
information inside the GraphQL context, which the AuthMiddlewareStack wrapper
above will provide. It might be apparent by now, there's no reason at all why
you couldn't run a Channels server without any Django ASGI application at all.
However, take care to ensure you run `django.setup()` instead of
`get_asgi_application()`, if you need any Django ORM or other Django features in
Strawberry.

### Running our example

First run your asgi application _(The ProtocolTypeRouter)_ using your asgi
server. If you are coming from the channels tutorial, there is no difference.
Then open three different tabs on your browser and go to the following URLs:

1. `localhost:8000/graphql`
2. `localhost:8000/graphql`
3. `localhost:8000/chat`

If you want, you can run 3 different instances of your application with
different ports it should work the same!

On tab #1 start the subscription:

```graphql
subscription SubscribeToChatRooms {
  joinChatRooms(
    rooms: [{ roomName: "room1" }, { roomName: "room2" }]
    user: "foo"
  ) {
    roomName
    message
    currentUser
  }
}
```

On tab #2 we will run `sendChatMessage` mutation:

```graphql
mutation echo {
  sendChatMessage(message: "hello room 1", room: { roomName: "room1" })
}
```

On tab #3 we will join the room you subscribed to ("room1") and start chatting.
Before we do that there is a slight change we need to make in the `ChatConsumer`
you created with channels in order to make it compatible with our
`ChatRoomMessage` type.

```python
# Send message to room group
await self.channel_layer.group_send(
    self.room_group_name,
    {
        "type": "chat.message",
        "room_id": self.room_group_name,  # <<< here is the change
        "message": f"process is {os.getpid()}, Thread is {threading.current_thread().name}"
        f" -> {message}",
    },
)
```

Look here for some more complete examples:

1. The
   [Strawberry Examples repo](https://github.com/strawberry-graphql/examples)
   contains a basic example app demonstrating subscriptions with Channels.

---

### Confirming GraphQL Subscriptions

By default no confirmation message is sent to the GraphQL client once the
subscription has started. However, this is useful to be able to synchronize
actions and detect communication errors. The code below shows how the above
example can be adapted to send a null from the server to the client to confirm
that the subscription has successfully started. This includes confirming that
the Channels layer subscription has started.

```python
# mysite/gqlchat/subscription.py


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def join_chat_rooms(
        self,
        info: strawberry.Info,
        rooms: List[ChatRoom],
        user: str,
    ) -> AsyncGenerator[ChatRoomMessage | None, None]:
        ...
        async with ws.listen_to_channel("chat.message", groups=room_ids) as cm:
            yield None
            async for message in cm:
                if message["room_id"] in room_ids:
                    yield ChatRoomMessage(
                        room_name=message["room_id"],
                        message=message["message"],
                        current_user=user,
                    )
```

Note the change in return signature for `join_chat_rooms` and the `yield None`
after entering the `listen_to_channel` context manger.

## Testing

We provide a minimal application communicator (`GraphQLWebsocketCommunicator`)
for subscribing. Here is an example based on the tutorial above: _Make sure you
have pytest-async installed_

```python
from channels.testing import WebsocketCommunicator
import pytest
from myapp.asgi import application  # your channels asgi
from strawberry.channels.testing import GraphQLWebsocketCommunicator


@pytest.fixture
async def gql_communicator() -> GraphQLWebsocketCommunicator:
    client = GraphQLWebsocketCommunicator(application=application, path="/graphql")
    await client.gql_init()
    yield client
    await client.disconnect()


chat_subscription_query = """
                subscription fooChat {
                joinChatRooms(
                    rooms: [{ roomName: "room1" }, { roomName: "room2" }]
                    user: "foo"){
                        roomName
                        message
                        currentUser
                    }
                }
"""


@pytest.mark.asyncio
async def test_joinChatRooms_sends_welcome_message(gql_communicator):
    async for result in gql_communicator.subscribe(query=chat_subscription_query):
        data = result.data
        assert data["currentUser"] == "foo"
        assert "room1" in data["roomName"]
        assert "hello" in data["message"]
```

In order to test a real server connection we can use python
[gql client](https://github.com/graphql-python/gql) and channels
[`ChannelsLiveServerTestCase`](https://channels.readthedocs.io/en/latest/topics/testing.html#channelsliveservertestcase).

<Note>

This example is based on the extended `ChannelsLiveServerTestCase` class from
channels tutorial part 4. **You cannot run this test with a pytest session.**

</Note>

Add this test in your `ChannelsLiveServerTestCase` extended class:

```python
from gql import Client, gql
from gql.transport.websockets import WebsocketsTransport


def test_send_message_via_channels_chat_joinChatRooms_recieves(self):
    transport = WebsocketsTransport(url=self.live_server_ws_url + "/graphql")

    client = Client(
        transport=transport,
        fetch_schema_from_transport=False,
    )

    query = gql(chat_subscription_query)
    for index, result in enumerate(client.subscribe(query)):
        if index == 0 or 1:
            print(result)
        # because we subscribed to 2 rooms we received two welcome messages.
        elif index == 2:
            print(result)
            assert "hello from web browser" in result["joinChatRooms"]["message"]
            break

        try:
            self._enter_chat_room("room1")
            self._post_message("hello from web browser")
        finally:
            self._close_all_new_windows()
```

---

The HTTP and WebSockets protocol are handled by different base classes. HTTP
uses `GraphQLHTTPConsumer` and WebSockets uses `GraphQLWSConsumer`. Both of them
can be extended:

### Passing connection params

Connection parameters can be passed using the `connection_params` parameter of
the `GraphQLWebsocketCommunicator` class. This is particularily useful to test
websocket authentication.

```python
GraphQLWebsocketCommunicator(
    application=application,
    path="/graphql",
    connection_params={"token": "strawberry"},
)
```

## GraphQLHTTPConsumer (HTTP)

### Options

`GraphQLHTTPConsumer` supports the same options as all other integrations:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

### Extending the consumer

The base `GraphQLHTTPConsumer` class can be extended by overriding any of the
following methods:

- `async def get_context(self, request: ChannelsRequest, response: TemporalResponse) -> Context`
- `async def get_root_value(self, request: ChannelsRequest) -> Optional[RootValue]`
- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: ChannelsRequest) -> ChannelsResponse`

#### Context

The default context returned by `get_context()` is a `dict` that includes the
following keys by default:

- `request`: A `ChannelsRequest` object with the following fields and methods:
  - `consumer`: The `GraphQLHTTPConsumer` instance for this connection
  - `body`: The request body
  - `headers`: A dict containing the headers of the request
  - `method`: The HTTP method of the request
  - `content_type`: The content type of the request
- `response` A `TemporalResponse` object, that can be used to influence the HTTP
  response:
  - `status_code`: The status code of the response, if there are no execution
    errors (defaults to `200`)
  - `headers`: Any additional headers that should be send with the response

#### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.channels import GraphQLHTTPConsumer, ChannelsRequest, ChannelsResponse


class MyGraphQLHTTPConsumer(GraphQLHTTPConsumer):
    async def render_graphql_ide(self, request: ChannelsRequest) -> ChannelsResponse:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return ChannelsResponse(content=custom_html, content_type="text/html")
```

## GraphQLWSConsumer (WebSockets / Subscriptions)

### Options

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `debug`: optional, defaults to `False`, whether to enable debug mode.
- `keep_alive`: optional, defaults to `False`, whether to enable keep alive mode
  for websockets.
- `keep_alive_interval`: optional, defaults to `1`, the interval in seconds for
  keep alive messages.
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the allowed WebSocket
  subscription protocols.

### Extending the consumer

The base `GraphQLWSConsumer` class can be extended by overriding any of the
following methods:

- `async def get_context(self, request: GraphQLWSConsumer, response: GraphQLWSConsumer) -> Context`
- `async def get_root_value(self, request: GraphQLWSConsumer) -> Optional[RootValue]`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def on_ws_connect(self, context: Context) -> Union[UnsetType, None, Dict[str, object]]`

### on_ws_connect

By overriding `on_ws_connect` you can customize the behavior when a `graphql-ws`
or `graphql-transport-ws` connection is established. This is particularly useful
for authentication and authorization. By default, all connections are accepted.

To manually accept a connection, return `strawberry.UNSET` or a connection
acknowledgment payload. The acknowledgment payload will be sent to the client.

Note that the legacy protocol does not support `None`/`null` acknowledgment
payloads, while the new protocol does. Our implementation will treat
`None`/`null` payloads the same as `strawberry.UNSET` in the context of the
legacy protocol.

To reject a connection, raise a `ConnectionRejectionError`. You can optionally
provide a custom error payload that will be sent to the client when the legacy
GraphQL over WebSocket protocol is used.

```python
from typing import Dict
from strawberry.exceptions import ConnectionRejectionError
from strawberry.channels import GraphQLWSConsumer


class MyGraphQLWSConsumer(GraphQLWSConsumer):
    async def on_ws_connect(self, context: Dict[str, object]):
        connection_params = context["connection_params"]

        if not isinstance(connection_params, dict):
            # Reject without a custom graphql-ws error payload
            raise ConnectionRejectionError()

        if connection_params.get("password") != "secret":
            # Reject with a custom graphql-ws error payload
            raise ConnectionRejectionError({"reason": "Invalid password"})

        if username := connection_params.get("username"):
            # Accept with a custom acknowledgment payload
            return {"message": f"Hello, {username}!"}

        # Accept without a acknowledgment payload
        return await super().on_ws_connect(context)
```

### Context

The default context returned by `get_context()` is a `dict` and it includes the
following keys by default:

- `request`: The `GraphQLWSConsumer` instance of the current connection. It can
  be used to access the connection scope, e.g. `info.context["ws"].headers`
  allows access to any headers.
- `ws`: The same as `request`
- `connection_params`: Any `connection_params`, see
  [Authenticating Subscriptions](/docs/general/subscriptions#authenticating-subscriptions)

## Example for defining a custom context

Here is an example for extending the base classes to offer a different context
object in your resolvers. For the HTTP integration, you can also have properties
to access the current user and the session. Both properties depend on the
`AuthMiddlewareStack` wrapper.

```
/* Detailed source-code truncated for AI context efficiency. */
```

You can import and use the extended `GraphQLHTTPConsumer` and
`GraphQLWSConsumer` classes in your `myproject.asgi.py` file as shown before.

---

## API

### GraphQLProtocolTypeRouter

A helper for creating a common strawberry-django
[`ProtocolTypeRouter`](https://channels.readthedocs.io/en/stable/topics/routing.html#protocoltyperouter)
Implementation.

Example usage:

```python
from strawberry.channels import GraphQLProtocolTypeRouter
from django.core.asgi import get_asgi_application

django_asgi = get_asgi_application()

from myapi import schema

application = GraphQLProtocolTypeRouter(
    schema,
    django_application=django_asgi,
)
```

This will route all requests to /graphql on either HTTP or websockets to us, and
everything else to the Django application.

### ChannelsConsumer

Strawberries extended
[`AsyncConsumer`](https://channels.readthedocs.io/en/stable/topics/consumers.html#consumers).

Every graphql session will have an instance of this class inside
`info.context["ws"]` (WebSockets) or `info.context["request"].consumer` (HTTP).

#### properties

```python
@contextlib.asynccontextmanager
async def listen_to_channel(
    self,
    type: str,
    *,
    timeout: float | None = None,
    groups: Sequence[str] | None = None,
) -> AsyncGenerator[Any, None]: ...
```

- `type` - The type of the message to wait for, equivalent to `scope['type']`
- `timeout` - An optional timeout to wait for each subsequent message.
- `groups` - list of groups to yield messages from threw channel layer.

---

### Integrations Creating An Integration (`docs/integrations/creating-an-integration.md`)

---
title: Adding an integration
---

# Adding an integration

Strawberry provides a set of integrations with other libraries, such as Django,
FastAPI, Flask, and more, but you can also add your own integration. This guide
will show you how to do that.

## Base views

Strawberry includes two base views that you can use to create your own
integrations:

- `SyncBaseHTTPView`: a base view for synchronous integrations
- `AsyncBaseHTTPView`: a base view for asynchronous integrations

Both views are provides the same API, with the main difference being that the
`AsyncBaseHTTPView`'s methods are async.

## Creating a view

To create a view, you need to create a class that inherits from either
`SyncBaseHTTPView` or `AsyncBaseHTTPView` and implement the `get_root_value`
method. Here is an example of a view that inherits from `AsyncBaseHTTPView`:

```python
from strawberry.http.async_base_view import AsyncBaseHTTPView
from strawberry.http.temporal_response import TemporalResponse
from strawberry.http.typevars import Context, RootValue


class MyView(
    AsyncBaseHTTPView[
        MyRequest,
        MyResponse,
        TemporalResponse,
        Context,
        RootValue,
    ]
):
    @property
    def allow_queries_via_get(self) -> bool:
        # this will usually be a setting on the view
        return True

    async def get_sub_response(self, request: MyRequest) -> TemporalResponse:
        return TemporalResponse(status_code=200)

    async def get_context(self, request: Request, response: SubResponse) -> Context:
        return {"request": request, "response": response}

    async def get_root_value(self, request: Request) -> Optional[RootValue]:
        return None

    def render_graphql_ide(self, request: Request) -> Response: ...

    def create_response(
        self, response_data: GraphQLHTTPResponse, sub_response: SubResponse
    ) -> Response: ...
```

The methods above are the bare minimum that you need to implement to create a
view. They are all required, but you can also override other methods to change
the behaviour of the view.

On top of that we also need a request adapter, here's the base class for the
async version:

```python
from strawberry.http.types import HTTPMethod, QueryParams, FormData


class AsyncHTTPRequestAdapter:
    @property
    def query_params(self) -> Mapping[str, Optional[Union[str, List[str]]]]: ...

    @property
    def method(self) -> HTTPMethod: ...

    @property
    def headers(self) -> Mapping[str, str]: ...

    @property
    def content_type(self) -> Optional[str]: ...

    async def get_body(self) -> Union[bytes, str]: ...

    async def get_form_data(self) -> FormData: ...
```

This request adapter will be used to get the request data from the request
object. You can specify the request adapter to use by setting the
`request_adapter_class` attribute on the view.

```python
class MyView(
    AsyncBaseHTTPView[
        MyRequest,
        MyResponse,
        TemporalResponse,
        Context,
        RootValue,
    ]
):
    request_adapter_class = MyRequestAdapter
```

Finally you need to execute the operation, the base view provides a `run` method
that you can use to do that:

```python
from strawberry.http.exceptions import HTTPException


class MyView(
    AsyncBaseHTTPView[
        MyRequest,
        MyResponse,
        TemporalResponse,
        Context,
        RootValue,
    ]
):
    ...

    async def get(self, request: MyRequest) -> MyResponse:
        try:
            return await self.run(request)
        except HTTPException as e:
            response = Response(e.reason, status_code=e.status_code)
```

---

### Integrations Django (`docs/integrations/django.md`)

---
title: Django
---

# Django

Strawberry comes with a basic
[Django integration](https://github.com/strawberry-graphql/strawberry-graphql-django).
It provides a view that you can use to serve your GraphQL schema:

```python
from django.urls import path
from django.views.decorators.csrf import csrf_exempt

from strawberry.django.views import GraphQLView

from api.schema import schema

urlpatterns = [
    path("graphql/", csrf_exempt(GraphQLView.as_view(schema=schema))),
]
```

Strawberry only provides a GraphQL view for Django,
[Strawberry GraphQL Django](https://github.com/strawberry-graphql/strawberry-graphql-django)
provides integration with the models. `import strawberry_django` should do the
same as `import strawberry.django` if both libraries are installed.

You'd also need to add `strawberry_django` to the `INSTALLED_APPS` of your
project, this is needed to provide the template for the GraphiQL interface.

## Options

The `GraphQLView` accepts the following arguments:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

## Deprecated options

The following options are deprecated and will be removed in a future release:

- `json_encoder`: optional JSON encoder, defaults to `DjangoJSONEncoder`, will
  be used to serialize the data.
- `json_dumps_params`: optional dictionary of keyword arguments to pass to the
  `json.dumps` call used to generate the response. To get the most compact JSON
  representation, you should specify `{"separators": (",", ":")}`, defaults to
  `None`.

You can extend the view and override `encode_json` to customize the JSON
encoding process.

## Extending the view

We allow to extend the base `GraphQLView`, by overriding the following methods:

- `def get_context(self, request: HttpRequest, response: HttpResponse) -> Context`
- `def get_root_value(self, request: HttpRequest) -> Optional[RootValue]`
- `def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `def render_graphql_ide(self, request: HttpRequest) -> HttpResponse`

### get_context

`get_context` allows to provide a custom context object that can be used in your
resolver. You can return anything here, by default we return a
`StrawberryDjangoContext` object.

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def user(self, info: strawberry.Info) -> str:
        return str(info.context.request.user)
```

or in case of a custom context:

```python
import strawberry
from strawberry.django.views import GraphQLView
from django.http import HttpRequest, HttpResponse


class MyGraphQLView(GraphQLView):
    def get_context(self, request: HttpRequest, response: HttpResponse):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called "example".

Then we use the context in a resolver, the resolver will return "1" in this
case.

### get_root_value

`get_root_value` allows to provide a custom root value for your schema, this is
probably not used a lot but it might be useful in certain situations.

Here's an example:

```python
import strawberry
from strawberry.django.views import GraphQLView
from django.http import HttpRequest


class MyGraphQLView(GraphQLView):
    def get_root_value(self, request: HttpRequest):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we are returning a Query where the name is "Patrick", so we when requesting
the field name we'll return "Patrick" in this case.

### process_result

`process_result` allows to customize and/or process results before they are sent
to the clients. This can be useful logging errors or hiding them (for example to
hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the request
and the execution results.

```python
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult
from strawberry.django.views import GraphQLView
from django.http import HttpRequest


class MyGraphQLView(GraphQLView):
    def process_result(
        self, request: HttpRequest, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP and WebSocket JSON
requests. By default we use `json.loads` but you can override this method to use
a different decoder.

```python
from strawberry.django.views import GraphQLView
from typing import Union
import orjson


class MyGraphQLView(GraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.django.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can provide the `graphql/graphiql.html`
template, which will be used instead of the configured IDE.

Alternatively, you can override the `render_graphql_ide` method:

```python
from strawberry.django.views import GraphQLView
from django.http import HttpResponse, HttpRequest
from django.template.loader import render_to_string


class MyGraphQLView(GraphQLView):
    def render_graphql_ide(self, request: HttpRequest) -> HttpResponse:
        content = render_to_string("myapp/my_graphql_ide_template.html")

        return HttpResponse(content)
```

# Async Django

Strawberry also provides an async view that you can use with Django's ASGI
support:

```python
from django.urls import path

from strawberry.django.views import AsyncGraphQLView

from api.schema import schema

urlpatterns = [
    path("graphql/", AsyncGraphQLView.as_view(schema=schema)),
]
```

You'd also need to add `strawberry_django` to the `INSTALLED_APPS` of your
project, this is needed to provide the template for the GraphiQL interface.

## Important Note: Django ORM and Async Context

When using `AsyncGraphQLView`, you may encounter a `SynchronousOnlyOperation`
error if your resolvers access Django's ORM directly:

```text
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
```

This occurs because Django's ORM is synchronous by default and cannot be called
directly from async contexts like the `AsyncGraphQLView`. Here are two
solutions:

### Solution 1: Use the async version of the ORM methods

Instead of using the standard version of the ORM methods, you can usually use an
async version, for example, in addition to `get` Django also provides `aget`
than can be used in an async context:

```python
import strawberry
from django.contrib.auth.models import User


@strawberry.type
class Query:
    @strawberry.field
    @staticmethod
    async def user_name(id: strawberry.ID) -> str:
        # Note: this is a simple example, you'd normally just return
        # a full user instead of making a resolver to get a user's name
        # by id. This is just to explain the async issues with Django :)

        user = await User.objects.aget(id)
        # This would cause SynchronousOnlyOperation error:
        # user = User.objects.get(id)

        return user.name
```

You can find all the supported methods in the
[Asynchronous support guide](https://docs.djangoproject.com/en/5.2/topics/async/)
on Django's website.

### Solution 2: Use `sync_to_async`

While some ORM methods have an async equivalent, not all of them do, in that
case you can wrap your ORM operations with Django's `sync_to_async`:

```python
import strawberry
from django.contrib.auth.models import User
from asgiref.sync import sync_to_async


@strawberry.type
class Query:
    @strawberry.field
    async def users(self) -> list[str]:
        # This would cause SynchronousOnlyOperation error:
        # return [user.username for user in User.objects.all()]

        # Correct way using sync_to_async:
        users = await sync_to_async(list)(User.objects.all())

        return [user.username for user in users]
```

### Solution 3: Use `strawberry_django` (Recommended)

The `strawberry_django` package automatically handles async/sync compatibility.
Use `strawberry_django.field` instead of `strawberry.field`:

```python
import strawberry_django
from django.contrib.auth.models import User


@strawberry_django.type(User)
class UserType:
    username: str
    email: str


@strawberry.type
class Query:
    # This automatically works with both sync and async views
    users: list[UserType] = strawberry_django.field()
```

We recommend using the `strawberry_django` package for Django ORM integration as
it provides automatic async/sync compatibility and additional Django-specific
features.

## Options

The `AsyncGraphQLView` accepts the following arguments:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.

## Extending the view

The base `AsyncGraphQLView` class can be extended by overriding any of the
following methods:

- `async def get_context(self, request: HttpRequest, response: HttpResponse) -> Context`
- `async def get_root_value(self, request: HttpRequest) -> Optional[RootValue]`
- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: HttpRequest) -> HttpResponse`

### get_context

`get_context` allows to provide a custom context object that can be used in your
resolver. You can return anything here, by default we return a dictionary with
the request.

```python
import strawberry
from strawberry.django.views import AsyncGraphQLView
from django.http import HttpRequest, HttpResponse


class MyGraphQLView(AsyncGraphQLView):
    async def get_context(self, request: HttpRequest, response: HttpResponse):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called "example".

Then we use the context in a resolver, the resolver will return "1" in this
case.

### get_root_value

`get_root_value` allows to provide a custom root value for your schema, this is
probably not used a lot but it might be useful in certain situations.

Here's an example:

```python
import strawberry
from strawberry.django.views import AsyncGraphQLView
from django.http import HttpRequest


class MyGraphQLView(AsyncGraphQLView):
    async def get_root_value(self, request: HttpRequest):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we are returning a Query where the name is "Patrick", so we when requesting
the field name we'll return "Patrick" in this case.

### process_result

`process_result` allows to customize and/or process results before they are sent
to the clients. This can be useful logging errors or hiding them (for example to
hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the request
and the execution results.

```python
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult
from strawberry.django.views import AsyncGraphQLView
from django.http import HttpRequest


class MyGraphQLView(AsyncGraphQLView):
    async def process_result(
        self, request: HttpRequest, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP and WebSocket JSON
requests. By default we use `json.loads` but you can override this method to use
a different decoder.

```python
from strawberry.django.views import AsyncGraphQLView
from typing import Union
import orjson


class MyGraphQLView(AsyncGraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.django.views import AsyncGraphQLView


class MyGraphQLView(AsyncGraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can provide the `graphql/graphiql.html`
template, which will be used instead of the configured IDE.

Alternatively, you can override the `render_graphql_ide` method:

```python
from strawberry.django.views import AsyncGraphQLView
from django.http import HttpResponse
from django.template.loader import render_to_string


class MyGraphQLView(AsyncGraphQLView):
    async def render_graphql_ide(self, request: HttpRequest) -> HttpResponse:
        content = render_to_string("myapp/my_graphql_ide_template.html")

        return HttpResponse(content)
```

## Subscriptions

Subscriptions run over websockets and thus depend on
[channels](https://channels.readthedocs.io/). Take a look at our
[channels integration](./channels.md) page for more information regarding it.

---

### Integrations Fastapi (`docs/integrations/fastapi.md`)

---
title: FastAPI
---

# FastAPI

Strawberry provides support for [FastAPI](https://fastapi.tiangolo.com/) with a
custom
[APIRouter](https://fastapi.tiangolo.com/tutorial/bigger-applications/#apirouter)
called `GraphQLRouter`.

Before using Strawberry's FastAPI support make sure you install all the required
dependencies by running:

```shell
pip install 'strawberry-graphql[fastapi]'
```

See the example below for integrating FastAPI with Strawberry:

```python
import strawberry

from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"


schema = strawberry.Schema(Query)

graphql_app = GraphQLRouter(schema)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

<Note>

Both FastAPI and Strawberry support sync and async functions, but their behavior
is different.

FastAPI processes sync endpoints in a threadpool and async endpoints using the
event loop. However, Strawberry processes sync and async fields using the event
loop, which means that using a sync `def` will block the entire worker.

It is recommended to use `async def` for all of your fields if you want to be
able to handle concurrent request on a single worker. If you can't use async,
make sure you wrap blocking code in a suspending thread, for example using
`starlette.concurrency.run_in_threadpool`.

</Note>

## Options

The `GraphQLRouter` accepts the following options:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `context_getter`: optional FastAPI dependency for providing custom context
  value.
- `root_value_getter`: optional FastAPI dependency for providing custom root
  value.
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

### context_getter

The `context_getter` option allows you to provide a custom context object that
can be used in your resolver. `context_getter` is a
[FastAPI dependency](https://fastapi.tiangolo.com/tutorial/dependencies/) and
can inject other dependencies if you so wish.

There are two options at your disposal here:

1. Define your custom context as a dictionary,
2. Define your custom context as a class.

If no context is supplied, then the default context returned is a dictionary
containing the request, the response, and any background tasks.

However, you can define a class-based custom context inline with
[FastAPI practice](https://fastapi.tiangolo.com/tutorial/dependencies/classes-as-dependencies/).
If you choose to do this, you must ensure that your custom context class
inherits from `BaseContext` or an `InvalidCustomContext` exception is raised.

For dictionary-based custom contexts, an example might look like the following.

```python
import strawberry

from fastapi import FastAPI, Depends, Request, WebSocket, BackgroundTasks
from strawberry.fastapi import GraphQLRouter


def custom_context_dependency() -> str:
    return "John"


async def get_context(
    custom_value=Depends(custom_context_dependency),
):
    return {
        "custom_value": custom_value,
    }


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return f"Hello {info.context['custom_value']}"


schema = strawberry.Schema(Query)

graphql_app = GraphQLRouter(
    schema,
    context_getter=get_context,
)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

Here we are returning a custom context dictionary that contains one extra item
called "custom*value", which is injected from `custom_context_dependency`. This
value exists alongside `request`, `response`, and `background_tasks` in the
`info.context` \_dictionary* and so it requires `['request']` indexing.

Then we use the context in a resolver. The resolver will return "Hello John" in
this case.

For class-based custom contexts, an example might look like the following.

```python
import strawberry

from fastapi import FastAPI, Depends, Request, WebSocket, BackgroundTasks
from strawberry.fastapi import BaseContext, GraphQLRouter


class CustomContext(BaseContext):
    def __init__(self, greeting: str, name: str):
        self.greeting = greeting
        self.name = name


def custom_context_dependency() -> CustomContext:
    return CustomContext(greeting="you rock!", name="John")


async def get_context(
    custom_context=Depends(custom_context_dependency),
):
    return custom_context


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return f"Hello {info.context.name}, {info.context.greeting}"


schema = strawberry.Schema(Query)

graphql_app = GraphQLRouter(
    schema,
    context_getter=get_context,
)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

In this case, we are returning a custom context class that inherits from
BaseContext with fields `name` and `greeting`, which is also injected by
`custom_context_dependency`. These custom values exist alongside `request`,
`response`, and `background_tasks` in the `info.context` _class_ and so it
requires `.request` indexing.

Then we use the context in a resolver. The resolver will return “Hello John, you
rock!” in this case.

#### Setting background tasks

Similarly,
[background tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/?h=background)
can be added via the context:

```python
import strawberry

from fastapi import FastAPI, BackgroundTasks
from strawberry.fastapi import GraphQLRouter


async def notify_new_flavour(name: str):
    print(name)


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"


@strawberry.type
class Mutation:
    @strawberry.mutation
    def create_flavour(self, name: str, info: strawberry.Info) -> bool:
        info.context["background_tasks"].add_task(notify_new_flavour, name)
        return True


schema = strawberry.Schema(Query, Mutation)

graphql_app = GraphQLRouter(schema)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

If using a custom context class, then background tasks should be stored within
the class object as `.background_tasks`.

### root_value_getter

The `root_value_getter` option allows you to provide a custom root value for
your schema. This is most likely a rare usecase but might be useful in certain
situations.

Here's an example:

```python
import strawberry

from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter


async def get_root_value():
    return Query(name="Patrick")


@strawberry.type
class Query:
    name: str


schema = strawberry.Schema(Query)

graphql_app = GraphQLRouter(
    schema,
    root_value_getter=get_root_value,
)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

Here we are returning a Query where the name is "Patrick", so when we request
the field name we'll return "Patrick".

## Extending the router

The base `GraphQLRouter` class can be extended by overriding any of the
following methods:

- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: Request) -> HTMLResponse`
- `async def on_ws_connect(self, context: Context) -> Union[UnsetType, None, Dict[str, object]]`

`GraphQLRouter` is generic over the context and root value types. Type checkers
can usually infer these types when the router is instantiated directly. When
subclassing the router, specify any custom context or root value types on the
base class to preserve their precise types:

```python
class MyGraphQLRouter(GraphQLRouter[MyContext, MyRootValue]):
    pass
```

The context defaults to the context types supported by the FastAPI integration,
while the root value defaults to `None`. You can therefore omit the root value
type when only the context is customized: `GraphQLRouter[MyContext]`. Apply the
same type arguments to explicit `GraphQLRouter` variable annotations, or omit
the redundant annotation and let the type checker infer the concrete subclass.

### process_result

The `process_result` option allows you to customize and/or process results
before they are sent to the clients. This can be useful for logging errors or
hiding them (for example to hide internal exceptions).

It needs to return a `GraphQLHTTPResponse` object and accepts the request and
execution results.

```python
from starlette.requests import Request
from strawberry.fastapi import GraphQLRouter
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult


class MyGraphQLRouter(GraphQLRouter):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP and WebSocket JSON
requests. By default we use `json.loads` but you can override this method to use
a different decoder.

```python
from strawberry.fastapi import GraphQLRouter
from typing import Union
import orjson


class MyGraphQLRouter(GraphQLRouter):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
from strawberry.fastapi import GraphQLRouter
import json


class MyGraphQLRouter(GraphQLRouter):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.fastapi import GraphQLRouter
from starlette.responses import HTMLResponse, Response
from starlette.requests import Request


class MyGraphQLRouter(GraphQLRouter):
    async def render_graphql_ide(self, request: Request) -> HTMLResponse:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return HTMLResponse(custom_html)
```

### on_ws_connect

By overriding `on_ws_connect` you can customize the behavior when a `graphql-ws`
or `graphql-transport-ws` connection is established. This is particularly useful
for authentication and authorization. By default, all connections are accepted.

To manually accept a connection, return `strawberry.UNSET` or a connection
acknowledgment payload. The acknowledgment payload will be sent to the client.

Note that the legacy protocol does not support `None`/`null` acknowledgment
payloads, while the new protocol does. Our implementation will treat
`None`/`null` payloads the same as `strawberry.UNSET` in the context of the
legacy protocol.

To reject a connection, raise a `ConnectionRejectionError`. You can optionally
provide a custom error payload that will be sent to the client when the legacy
GraphQL over WebSocket protocol is used.

```python
from strawberry.exceptions import ConnectionRejectionError
from strawberry.fastapi import BaseContext, GraphQLRouter


class Context(BaseContext):
    pass


class MyGraphQLRouter(GraphQLRouter[Context]):
    async def on_ws_connect(self, context: Context):
        connection_params = context.connection_params

        if not isinstance(connection_params, dict):
            # Reject without a custom graphql-ws error payload
            raise ConnectionRejectionError()

        if connection_params.get("password") != "secret":
            # Reject with a custom graphql-ws error payload
            raise ConnectionRejectionError({"reason": "Invalid password"})

        if username := connection_params.get("username"):
            # Accept with a custom acknowledgment payload
            return {"message": f"Hello, {username}!"}

        # Accept without a acknowledgment payload
        return await super().on_ws_connect(context)
```

---

### Integrations Flask (`docs/integrations/flask.md`)

---
title: Flask
---

# Flask

Strawberry comes with a basic Flask integration. It provides a view that you can
use to serve your GraphQL schema:

```python
from flask import Flask
from strawberry.flask.views import GraphQLView

from api.schema import schema

app = Flask(__name__)

app.add_url_rule(
    "/graphql",
    view_func=GraphQLView.as_view("graphql_view", schema=schema),
)

if __name__ == "__main__":
    app.run()
```

If you'd prefer to use an asynchronous view you can instead use the following
import which has the same interface as `GraphQLView`. This is helpful if using a
dataloader.

```python
from strawberry.flask.views import AsyncGraphQLView
```

## Options

The `GraphQLView` accepts the following options at the moment:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

## Extending the view

The base `GraphQLView` class can be extended by overriding any of the following
methods:

- `def get_context(self, request: Request, response: Response) -> Context`
- `def get_root_value(self, request: Request) -> Optional[RootValue]`
- `def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `def render_graphql_ide(self, request: Request) -> Response`

<Note>

Note that the `AsyncGraphQLView` can also be extended in the same way, but the
`get_context`, `get_root_value`, `process_result`, and `render_graphql_ide`
methods are asynchronous.

</Note>

### get_context

`get_context` allows to provide a custom context object that can be used in your
resolver. You can return anything here, by default we return a dictionary with
the request. By default; the `Response` object from `flask` is injected via the
parameters.

```python
import strawberry
from strawberry.flask.views import GraphQLView
from flask import Request, Response


class MyGraphQLView(GraphQLView):
    def get_context(self, request: Request, response: Response):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called "example".

Then we use the context in a resolver, the resolver will return "1" in this
case.

### get_root_value

`get_root_value` allows to provide a custom root value for your schema, this is
probably not used a lot but it might be useful in certain situations.

Here's an example:

```python
import strawberry
from strawberry.flask.views import GraphQLView
from flask import Request


class MyGraphQLView(GraphQLView):
    def get_root_value(self, request: Request):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we are returning a Query where the name is "Patrick", so we when requesting
the field name we'll return "Patrick" in this case.

### process_result

`process_result` allows to customize and/or process results before they are sent
to the clients. This can be useful logging errors or hiding them (for example to
hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the execution
result.

```python
from strawberry.flask.views import GraphQLView
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult


class MyGraphQLView(GraphQLView):
    def process_result(self, result: ExecutionResult) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP JSON requests. By default
we use `json.loads` but you can override this method to use a different decoder.

```python
from strawberry.flask.views import GraphQLView
from typing import Union
import orjson


class MyGraphQLView(GraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.flask.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.flask.views import GraphQLView
from flask import Request, Response


class MyGraphQLView(GraphQLView):
    def render_graphql_ide(self, request: Request) -> Response:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return Response(custom_html, status=200, content_type="text/html")
```

---

### Integrations Litestar (`docs/integrations/litestar.md`)

---
title: Litestar
---

# Litestar

Strawberry comes with an integration for [Litestar](https://litestar.dev/) by
providing a `make_graphql_controller` function that can be used to create a
GraphQL controller.

See the example below for integrating Litestar with Strawberry:

```python
import strawberry
from litestar import Litestar
from strawberry.litestar import make_graphql_controller


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
)

app = Litestar(route_handlers=[GraphQLController])
```

## Options

The `make_graphql_controller` function accepts the following options:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `path`: optional, defaults to ``, the path where the GraphQL endpoint will be
  mounted.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `context_getter`: optional Litestar dependency for providing custom context
  value.
- `root_value_getter`: optional Litestar dependency for providing custom root
  value.
- `debug`: optional, defaults to `False`, whether to enable debug mode.
- `keep_alive`: optional, defaults to `False`, whether to enable keep alive mode
  for websockets.
- `keep_alive_interval`: optional, defaults to `1`, the interval in seconds for
  keep alive messages.
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the allowed
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `connection_init_wait_timeout` optional, default to `timedelta(minutes=1)`,
  the maximum time to wait for the connection initialization message when using
  `graphql-transport-ws`
  [protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md#connectioninit)
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

### context_getter

The `context_getter` option allows you to provide a Litestar dependency that
return a custom context object that can be used in your resolver.

```python
import strawberry
from litestar import Request, Litestar
from strawberry.litestar import make_graphql_controller
from strawberry.types.info import Info


async def custom_context_getter():
    return {"custom": "context"}


@strawberry.type
class Query:
    @strawberry.field
    def hello(self, info: strawberry.Info[dict, None]) -> str:
        return info.context["custom"]


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
    context_getter=custom_context_getter,
)

app = Litestar(route_handlers=[GraphQLController])
```

The `context_getter` is a standard Litestar dependency and can receive any
existing dependency:

```python
import strawberry
from litestar import Request, Litestar
from strawberry.litestar import make_graphql_controller
from strawberry.types.info import Info
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import User
from sqlalchemy import select


async def custom_context_getter(request: Request, db_session: AsyncSession):
    return {"user": request.user, "session": db_session}


@strawberry.type
class Query:
    @strawberry.field
    async def hello(self, info: strawberry.Info[dict, None]) -> str:
        session: AsyncSession = info.context["session"]
        user: User = info.context["user"]

        query = select(User).where(User.id == user.id)
        user = (await session.execute((query))).scalar_one()
        return f"Hello {user.first_name}"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
    context_getter=custom_context_getter,
)

app = Litestar(route_handlers=[GraphQLController])
```

You can also use a class-based custom context. To do this, you must inherit from
`BaseContext` [msgspec Struct](https://jcristharif.com/msgspec/structs.html) or
an `InvalidCustomContext` exception will be raised.

```python
import strawberry
from litestar import Request, Litestar
from strawberry.litestar import make_graphql_controller, BaseContext
from strawberry.types.info import Info
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import User
from sqlalchemy import select


class CustomContext(BaseContext):
    user: User
    session: AsyncSession


async def custom_context_getter(
    request: Request, db_session: AsyncSession
) -> CustomContext:
    return CustomContext(user=request.user, session=db_session)


@strawberry.type
class Query:
    @strawberry.field
    async def hello(self, info: strawberry.Info[CustomContext, None]) -> str:
        session: AsyncSession = info.context.session
        user: User = info.context.user

        query = select(User).where(User.id == user.id)
        user = (await session.execute((query))).scalar_one()
        return f"Hello {user.first_name}"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
    context_getter=custom_context_getter,
)

app = Litestar(route_handlers=[GraphQLController])
```

#### Context typing

In our previous example using class based context, the actual runtime context a
`CustomContext` type. Because it inherits from `BaseContext`, the `request`,
`socket` and `response` attributes are typed as optional.

When inside a query/mutation resolver, `request` and `response` are always set
and `socket` is only set in subscriptions.

To distinguish theses cases typing wise, the integration provides two classes
that will help you to enforce strong typing:

```python
from strawberry.litestar import HTTPContextType, WebSocketContextType
```

These classes does not actually exists at runtime, they are intended to be used
to define a custom `Info` type with proper context typing. Taking over our
previous example with class based custom context, here it how we can define two
`Info` types for both queries/mutations and subscriptions:

```
/* Detailed source-code truncated for AI context efficiency. */
```

### root_value_getter

The `root_value_getter` option allows you to provide a custom root value that
can be used in your resolver

```python
import strawberry
from litestar import Request, Litestar
from strawberry.litestar import make_graphql_controller


@strawberry.type
class Query:
    example: str = "Hello World"

    @strawberry.field
    def hello(self) -> str:
        return self.example


def custom_get_root_value():
    return Query()


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
    root_value_getter=custom_get_root_value,
)

app = Litestar(route_handlers=[GraphQLController])
```

## Extending the controller

The base `GraphQLController` class returned by `make_graphql_controller` can be
extended by overriding any of the following methods:

- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: Request) -> Response`
- `async def on_ws_connect(self, context: Context) -> Union[UnsetType, None, Dict[str, object]]`

### process_result

The `process_result` option allows you to customize and/or process results
before they are sent to the clients. This can be useful for logging errors or
hiding them (for example to hide internal exceptions).

It needs to return a `GraphQLHTTPResponse` object and accepts the request and
execution results.

```python
import strawberry
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult
from strawberry.litestar import make_graphql_controller
from litestar import Request


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
)


class MyGraphQLController(GraphQLController):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP and WebSocket JSON
requests. By default we use `json.loads` but you can override this method to use
a different decoder.

```python
import strawberry
import orjson
from strawberry.litestar import make_graphql_controller
from typing import Union


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
)


class MyGraphQLController(GraphQLController):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
import strawberry
from strawberry.litestar import make_graphql_controller


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
)


class MyGraphQLController(GraphQLController):
    def encode_json(self, data: object) -> bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
import strawberry
from strawberry.litestar import make_graphql_controller
from litestar import MediaType, Request, Response


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
)


class MyGraphQLController(GraphQLController):
    async def render_graphql_ide(self, request: Request) -> Response:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return Response(custom_html, media_type=MediaType.HTML)
```

### on_ws_connect

By overriding `on_ws_connect` you can customize the behavior when a `graphql-ws`
or `graphql-transport-ws` connection is established. This is particularly useful
for authentication and authorization. By default, all connections are accepted.

To manually accept a connection, return `strawberry.UNSET` or a connection
acknowledgment payload. The acknowledgment payload will be sent to the client.

Note that the legacy protocol does not support `None`/`null` acknowledgment
payloads, while the new protocol does. Our implementation will treat
`None`/`null` payloads the same as `strawberry.UNSET` in the context of the
legacy protocol.

To reject a connection, raise a `ConnectionRejectionError`. You can optionally
provide a custom error payload that will be sent to the client when the legacy
GraphQL over WebSocket protocol is used.

```python
import strawberry
from typing import Dict
from strawberry.exceptions import ConnectionRejectionError
from strawberry.litestar import make_graphql_controller


@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "world"


schema = strawberry.Schema(Query)

GraphQLController = make_graphql_controller(
    schema,
    path="/graphql",
)


class MyGraphQLController(GraphQLController):
    async def on_ws_connect(self, context: Dict[str, object]):
        connection_params = context["connection_params"]

        if not isinstance(connection_params, dict):
            # Reject without a custom graphql-ws error payload
            raise ConnectionRejectionError()

        if connection_params.get("password") != "secret":
            # Reject with a custom graphql-ws error payload
            raise ConnectionRejectionError({"reason": "Invalid password"})

        if username := connection_params.get("username"):
            # Accept with a custom acknowledgment payload
            return {"message": f"Hello, {username}!"}

        # Accept without a acknowledgment payload
        return await super().on_ws_connect(context)
```

---

### Integrations Pydantic (`docs/integrations/pydantic.md`)

---
title: Pydantic support
experimental: true
---

# Pydantic support

Strawberry comes with support for
[Pydantic](https://pydantic-docs.helpmanual.io/). This allows for the creation
of Strawberry types from pydantic models without having to write code twice.

Here's a basic example of how this works, let's say we have a pydantic Model for
a user, like this:

```python
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str
    signup_ts: Optional[datetime] = None
    friends: List[int] = []
```

We can create a Strawberry type by using the
`strawberry.experimental.pydantic.type` decorator:

```python
import strawberry

from .models import User


@strawberry.experimental.pydantic.type(model=User)
class UserType:
    id: strawberry.auto
    name: strawberry.auto
    friends: strawberry.auto
```

The `strawberry.experimental.pydantic.type` decorator accepts a Pydantic model
and wraps a class that contains dataclass style fields with `strawberry.auto` as
the type annotation. The fields marked with `strawberry.auto` will inherit their
types from the Pydantic model.

If you want to include all of the fields from your Pydantic model, you can
instead pass `all_fields=True` to the decorator.

-> **Note** Care should be taken to avoid accidentally exposing fields that ->
weren't meant to be exposed on an API using this feature.

```python
import strawberry

from .models import User


@strawberry.experimental.pydantic.type(model=User, all_fields=True)
class UserType:
    pass
```

By default, computed fields are excluded. To also include all computed fields
pass `include_computed=True` to the decorator.

```python
import strawberry

from .models import User


@strawberry.experimental.pydantic.type(
    model=User, all_fields=True, include_computed=True
)
class UserType:
    pass
```

## Input types

Input types are similar to types; we can create one by using the
`strawberry.experimental.pydantic.input` decorator:

```python
import strawberry

from .models import User


@strawberry.experimental.pydantic.input(model=User)
class UserInput:
    id: strawberry.auto
    name: strawberry.auto
    friends: strawberry.auto
```

## Interface types

Interface types are similar to normal types; we can create one by using the
`strawberry.experimental.pydantic.interface` decorator:

```python
import strawberry
from pydantic import BaseModel
from typing import List


# pydantic types
class User(BaseModel):
    id: int
    name: str


class NormalUser(User):
    friends: List[int] = []


class AdminUser(User):
    role: int


# strawberry types
@strawberry.experimental.pydantic.interface(model=User)
class UserType:
    id: strawberry.auto
    name: strawberry.auto


@strawberry.experimental.pydantic.type(model=NormalUser)
class NormalUserType(UserType):  # note the base class
    friends: strawberry.auto


@strawberry.experimental.pydantic.type(model=AdminUser)
class AdminUserType(UserType):
    role: strawberry.auto
```

## Error Types

In addition to object types and input types, Strawberry allows you to create
"error types". You can use these error types to have a typed representation of
Pydantic errors in GraphQL. Let's see an example:

<CodeGrid>

```python
from pydantic import BaseModel, constr
import strawberry


class User(BaseModel):
    id: int
    name: constr(min_length=2)
    signup_ts: Optional[datetime] = None
    friends: List[int] = []


@strawberry.experimental.pydantic.error_type(model=User)
class UserError:
    id: strawberry.auto
    name: strawberry.auto
    friends: strawberry.auto
```

```graphql
type UserError {
  id: [String!]
  name: [String!]
  friends: [[String!]]
}
```

</CodeGrid>

where each field will hold a list of error messages

## Extending types

You can use the usual Strawberry syntax to add additional new fields to the
GraphQL type that aren't defined in the pydantic model

<CodeGrid>

```python
import strawberry
from pydantic import BaseModel

from .models import User


class User(BaseModel):
    id: int
    name: str


@strawberry.experimental.pydantic.type(model=User)
class User:
    id: strawberry.auto
    name: strawberry.auto
    age: int
```

```graphql
type User {
  id: Int!
  name: String!
  age: Int!
}
```

</CodeGrid>

## Converting types

The generated types won't run any pydantic validation. This is to prevent
confusion when extending types and also to be able to run validation exactly
where it is needed.

To convert a Pydantic instance to a Strawberry instance you can use
`from_pydantic` on the Strawberry type:

```python
import strawberry
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str


@strawberry.experimental.pydantic.type(model=User)
class UserType:
    id: strawberry.auto
    name: strawberry.auto


instance = User(id="123", name="Jake")

data = UserType.from_pydantic(instance)
```

If your Strawberry type includes additional fields that aren't defined in the
pydantic model, you will need to use the `extra` parameter of `from_pydantic` to
specify the values to assign to them.

```python
import strawberry
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str


@strawberry.experimental.pydantic.type(model=User)
class UserType:
    id: strawberry.auto
    name: strawberry.auto
    age: int


instance = User(id="123", name="Jake")

data = UserType.from_pydantic(instance, extra={"age": 10})
```

The data dictionary structure follows the structure of your data -- if you have
a list of `User`, you should send an `extra` that is the list of `User` with the
missing data (in this case, `age`).

You don't need to send all fields; data from the model is used first and then
the `extra` parameter is used to fill in any additional missing data.

To convert a Strawberry instance to a pydantic instance and trigger validation,
you can use `to_pydantic` on the Strawberry instance:

```python
import strawberry
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str


@strawberry.experimental.pydantic.input(model=User)
class UserInput:
    id: strawberry.auto
    name: strawberry.auto


input_data = UserInput(id="abc", name="Jake")

# this will run pydantic's validation
instance = input_data.to_pydantic()
```

## Constrained types

Strawberry supports
[pydantic constrained types](https://pydantic-docs.helpmanual.io/usage/types/#constrained-types).
Note that constraint is not enforced in the graphql type. Thus, we recommend
always working on the pydantic type such that the validation is enforced.

<CodeGrid>

```python
from pydantic import BaseModel, conlist
import strawberry


class Example(BaseModel):
    friends: conlist(str, min_items=1)


@strawberry.experimental.pydantic.input(model=Example, all_fields=True)
class ExampleGQL: ...


@strawberry.type
class Query:
    @strawberry.field()
    def test(self, example: ExampleGQL) -> None:
        # friends may be an empty list here
        print(example.friends)
        # calling to_pydantic() runs the validation and raises
        # an error if friends is empty
        print(example.to_pydantic().friends)


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

```graphql
input ExampleGQL {
  friends: [String!]!
}

type Query {
  test(example: ExampleGQL!): Void
}
```

</CodeGrid>

## Classes with `__get_validators__`

Pydantic BaseModels may define a custom type with
[`__get_validators__`](https://pydantic-docs.helpmanual.io/usage/types/#classes-with-__get_validators__)
logic. You will need to add a scalar type and add the mapping to the
`scalar_overrides` argument in the Schema class.

```python
import strawberry
from pydantic import BaseModel


class MyCustomType:
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        return MyCustomType()


class Example(BaseModel):
    custom: MyCustomType


@strawberry.experimental.pydantic.type(model=Example, all_fields=True)
class ExampleGQL: ...


MyScalarType = strawberry.scalar(
    MyCustomType,
    # or another function describing how to represent MyCustomType in the response
    serialize=str,
    parse_value=lambda v: MyCustomType(),
)


@strawberry.type
class Query:
    @strawberry.field()
    def test(self) -> ExampleGQL:
        return Example(custom=MyCustomType())


# Tells strawberry to convert MyCustomType into MyScalarType
schema = strawberry.Schema(query=Query, scalar_overrides={MyCustomType: MyScalarType})
```

## Custom Conversion Logic

Sometimes you might not want to translate your Pydantic model into Strawberry
using the logic provided in the library. Sometimes types in Pydantic are
unrepresentable in GraphQL (such as unions of scalar values) or structural
changes are needed before the data is exposed in the schema. In these cases,
there are two methods you can use to control the conversion logic more directly.

First, you can use a different type annotation in your Strawberry model for a
field type instead of using `strawberry.auto` to choose an equivalent type. This
allows you to do things like converting values to custom scalar types or
converting between basic types. Strawberry will call the constructor of the new
type annotation with the field value as input, so this only works when
conversion is possible through a constructor.

```python
import base64
import strawberry
from pydantic import BaseModel
from typing import Union, NewType


class User(BaseModel):
    id: Union[int, str]  # Not representable in GraphQL
    hash: bytes


Base64 = strawberry.scalar(
    NewType("Base64", bytes),
    serialize=lambda v: base64.b64encode(v).decode("utf-8"),
    parse_value=lambda v: base64.b64decode(v.encode("utf-8")),
)


@strawberry.experimental.pydantic.type(model=User)
class UserType:
    id: str  # Serialize int values to strings
    hash: Base64  # Use a custom scalar to serialize values


@strawberry.type
class Query:
    @strawberry.field
    def test() -> UserType:
        return UserType.from_pydantic(User(id=123, hash=b"abcd"))


schema = strawberry.Schema(query=Query)

print(schema.execute_sync("query { test { id, hash } }").data)
# {"test": {"id": "123", "hash": "YWJjZA=="}}
```

The other, more comprehensive, method for modifying the conversion logic is to
provide custom implementations of `from_pydantic` and `to_pydantic`. This allows
you full control over the conversion process and bypasses Strawberry's built in
conversion rules completely, while still registering the new type as a Pydantic
conversion type so it can be referenced in other models.

This is useful when you need to represent structures that are very different
from GraphQL standards, without changing the underlying Pydantic model. An
example would be a use case that uses a `dict` field to store some
semi-structured content, which is difficult to represent in GraphQL's strict
type system.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Integrations Quart (`docs/integrations/quart.md`)

---
title: Quart
---

# Quart

Strawberry comes with a basic Quart integration. It provides a view that you can
use to serve your GraphQL schema:

```python
from quart import Quart
from strawberry.quart.views import GraphQLView
from api.schema import schema

view = GraphQLView.as_view("graphql_view", schema=schema)

app = Quart(__name__)
app.add_url_rule("/graphql", view_func=view)
app.add_url_rule("/graphql", view_func=view, methods=["GET"], websocket=True)

if __name__ == "__main__":
    app.run()
```

## Options

The `GraphQLView` accepts the following options at the moment:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

## Extending the view

The base `GraphQLView` class can be extended by overriding any of the following
methods:

- `async def get_context(self, request: Request, response: Response) -> Context`
- `async def get_root_value(self, request: Request) -> Optional[RootValue]`
- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: Request) -> Response`
- `async def on_ws_connect(self, context: Context) -> Union[UnsetType, None, Dict[str, object]]`

### get_context

`get_context` allows to provide a custom context object that can be used in your
resolver. You can return anything here, by default we return a dictionary with
the request. By default; the `Response` object from Quart is injected via the
parameters.

```python
import strawberry
from strawberry.quart.views import GraphQLView
from quart import Request, Response


class MyGraphQLView(GraphQLView):
    async def get_context(self, request: Request, response: Response):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called "example".

Then we use the context in a resolver, the resolver will return "1" in this
case.

### get_root_value

`get_root_value` allows to provide a custom root value for your schema, this is
probably not used a lot but it might be useful in certain situations.

Here's an example:

```python
import strawberry
from strawberry.quart.views import GraphQLView
from quart import Request


class MyGraphQLView(GraphQLView):
    async def get_root_value(self, request: Request):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we are returning a Query where the name is "Patrick", so we when requesting
the field name we'll return "Patrick" in this case.

### process_result

`process_result` allows to customize and/or process results before they are sent
to the clients. This can be useful logging errors or hiding them (for example to
hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the execution
result.

```python
from strawberry.quart.views import GraphQLView
from strawberry.http import GraphQLHTTPResponse
from strawberry.types import ExecutionResult
from quart import Request


class MyGraphQLView(GraphQLView):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        data: GraphQLHTTPResponse = {"data": result.data}

        if result.errors:
            data["errors"] = [err.formatted for err in result.errors]

        return data
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP JSON requests. By default
we use `json.loads` but you can override this method to use a different decoder.

```python
from strawberry.quart.views import GraphQLView
from typing import Union
import orjson


class MyGraphQLView(GraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.quart.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.quart.views import GraphQLView
from quart import Request, Response


class MyGraphQLView(GraphQLView):
    async def render_graphql_ide(self, request: Request) -> Response:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return Response(custom_html)
```

### on_ws_connect

By overriding `on_ws_connect` you can customize the behavior when a `graphql-ws`
or `graphql-transport-ws` connection is established. This is particularly useful
for authentication and authorization. By default, all connections are accepted.

To manually accept a connection, return `strawberry.UNSET` or a connection
acknowledgment payload. The acknowledgment payload will be sent to the client.

Note that the legacy protocol does not support `None`/`null` acknowledgment
payloads, while the new protocol does. Our implementation will treat
`None`/`null` payloads the same as `strawberry.UNSET` in the context of the
legacy protocol.

To reject a connection, raise a `ConnectionRejectionError`. You can optionally
provide a custom error payload that will be sent to the client when the legacy
GraphQL over WebSocket protocol is used.

```python
from typing import Dict
from strawberry.exceptions import ConnectionRejectionError
from strawberry.quart.views import GraphQLView


class MyGraphQLView(GraphQLView):
    async def on_ws_connect(self, context: Dict[str, object]):
        connection_params = context["connection_params"]

        if not isinstance(connection_params, dict):
            # Reject without a custom graphql-ws error payload
            raise ConnectionRejectionError()

        if connection_params.get("password") != "secret":
            # Reject with a custom graphql-ws error payload
            raise ConnectionRejectionError({"reason": "Invalid password"})

        if username := connection_params.get("username"):
            # Accept with a custom acknowledgment payload
            return {"message": f"Hello, {username}!"}

        # Accept without an acknowledgment payload
        return await super().on_ws_connect(context)
```

---

### Integrations Sanic (`docs/integrations/sanic.md`)

---
title: Sanic
---

# Sanic

Strawberry comes with a basic [Sanic](https://github.com/sanic-org/sanic)
integration. It provides a view that you can use to serve your GraphQL schema:

```python
from strawberry.sanic.views import GraphQLView

from api.schema import Schema

app = Sanic(__name__)

app.add_route(
    GraphQLView.as_view(schema=schema, graphiql=True),
    "/graphql",
)
```

## Options

The `GraphQLView` accepts the following options at the moment:

- `schema`: mandatory, the schema created by `strawberry.Schema`.
- `graphql_ide`: optional, defaults to `"graphiql"`, allows to choose the
  GraphQL IDE interface (one of `graphiql`, `apollo-sandbox` or `pathfinder`) or
  to disable it by passing `None`.
- `allow_queries_via_get`: optional, defaults to `True`, whether to enable
  queries via `GET` requests
- `subscription_protocols`: optional, defaults to
  `(GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL)`, the enabled
  subscription protocols. Include `MULTIPART_SUBSCRIPTION_PROTOCOL` to enable
  multipart subscriptions or `GRAPHQL_SSE_PROTOCOL` to enable SSE.
- `multipart_uploads_enabled`: optional, defaults to `False`, controls whether
  to enable multipart uploads. Please make sure to consider the
  [security implications mentioned in the GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec/blob/master/readme.md#security)
  when enabling this feature.

## Extending the view

The base `GraphQLView` class can be extended by overriding any of the following
methods:

- `async def get_context(self, request: Request, response: TemporalResponse) -> Context`
- `async def get_root_value(self, request: Request) -> Optional[RootValue]`
- `async def process_result(self, request: Request, result: ExecutionResult) -> GraphQLHTTPResponse`
- `def decode_json(self, data: Union[str, bytes]) -> object`
- `def encode_json(self, data: object) -> str | bytes`
- `async def render_graphql_ide(self, request: Request) -> HTTPResponse`

### get_context

By overriding `GraphQLView.get_context` you can provide a custom context object
for your resolvers. You can return anything here; by default GraphQLView returns
a dictionary with the request.

```python
import strawberry
from strawberry.sanic.views import GraphQLView
from strawberry.http.temporal_response import TemporalResponse
from sanic.request import Request


class MyGraphQLView(GraphQLView):
    async def get_context(self, request: Request, response: TemporalResponse):
        return {"example": 1}


@strawberry.type
class Query:
    @strawberry.field
    def example(self, info: strawberry.Info) -> str:
        return str(info.context["example"])
```

Here we are returning a custom context dictionary that contains only one item
called `"example"`.

Then we can use the context in a resolver. In this case the resolver will return
`1`.

### get_root_value

By overriding `GraphQLView.get_root_value` you can provide a custom root value
for your schema. This is probably not used a lot but it might be useful in
certain situations.

Here's an example:

```python
import strawberry
from strawberry.sanic.views import GraphQLView
from sanic.request import Request


class MyGraphQLView(GraphQLView):
    async def get_root_value(self, request: Request):
        return Query(name="Patrick")


@strawberry.type
class Query:
    name: str
```

Here we configure a Query where requesting the `name` field will return
`"Patrick"` through the custom root value.

### process_result

By overriding `GraphQLView.process_result` you can customize and/or process
results before they are sent to a client. This can be useful for logging errors,
or even hiding them (for example to hide internal exceptions).

It needs to return an object of `GraphQLHTTPResponse` and accepts the execution
result.

```python
from strawberry.sanic.views import GraphQLView
from strawberry.http import GraphQLHTTPResponse, process_result
from strawberry.types import ExecutionResult
from sanic.request import Request


class MyGraphQLView(GraphQLView):
    async def process_result(
        self, request: Request, result: ExecutionResult
    ) -> GraphQLHTTPResponse:
        if result.errors:
            result.errors = [err.formatted for err in result.errors]

        return process_result(data)
```

In this case we are doing the default processing of the result, but it can be
tweaked based on your needs.

### decode_json

`decode_json` allows to customize the decoding of HTTP JSON requests. By default
we use `json.loads` but you can override this method to use a different decoder.

```python
from strawberry.sanic.views import GraphQLView
from typing import Union
import orjson


class MyGraphQLView(GraphQLView):
    def decode_json(self, data: Union[str, bytes]) -> object:
        return orjson.loads(data)
```

Make sure your code raises `json.JSONDecodeError` or a subclass of it if the
JSON cannot be decoded. The library shown in the example above, `orjson`, does
this by default.

### encode_json

`encode_json` allows to customize the encoding of HTTP and WebSocket JSON
responses. By default we use `json.dumps` but you can override this method to
use a different encoder.

```python
import json
from strawberry.sanic.views import GraphQLView


class MyGraphQLView(GraphQLView):
    def encode_json(self, data: object) -> str | bytes:
        return json.dumps(data, indent=2)
```

### render_graphql_ide

In case you need more control over the rendering of the GraphQL IDE than the
`graphql_ide` option provides, you can override the `render_graphql_ide` method.

```python
from strawberry.sanic.views import GraphQLView
from sanic.request import Request
from sanic.response import HTTPResponse, html


class MyGraphQLView(GraphQLView):
    async def render_graphql_ide(self, request: Request) -> HTTPResponse:
        custom_html = """<html><body><h1>Custom GraphQL IDE</h1></body></html>"""

        return html(custom_html)
```

---

### Integrations Starlette (`docs/integrations/starlette.md`)

---
title: Starlette
---

# Starlette

Strawberry provides support for [Starlette](https://www.starlette.io/) with the
ASGI integration.

Use `Route` and `WebSocketRoute` to integrate Strawberry with Starlette:

```python
from starlette.applications import Starlette
from starlette.routing import Route, WebSocketRoute
from strawberry.asgi import GraphQL

from api.schema import schema

graphql_app = GraphQL(schema)

app = Starlette(
    routes=[
        Route("/graphql", graphql_app),
        WebSocketRoute("/graphql", graphql_app),
    ]
)
```

For more information about Strawberry ASGI refer to
[the documentation on ASGI](./asgi.md)

---

### Operations Deployment (`docs/operations/deployment.md`)

---
title: Deployment
---

# Deployment

Before deploying your GraphQL app to production you should disable `GraphiQL`
and `Introspection`.

## Why are they a problem?

1. They can reveal sensitive information (e.g. internal business logic)

2. They make it easier for malicious parties to reverse engineer your GraphQL
   API

[See more on this topic](https://www.apollographql.com/blog/graphql/security/why-you-should-disable-graphql-introspection-in-production/)

## How to disable them

### GraphiQL

GraphiQL is useful during testing and development but should be disabled in
production by default.

It can be turned off by setting the `graphql_ide` option to `None`

See the Strawberry Options documentation for the integration you are using for
more information on how to disable it:

- [AIOHTTP](../integrations/aiohttp.md#options)
- [ASGI](../integrations/asgi.md#options)
- [Django](../integrations/django.md#options)
- [FastAPI](../integrations/fastapi.md#options)
- [Flask](../integrations/flask.md#options)
- [Quart](../integrations/quart.md#options)
- [Sanic](../integrations/sanic.md#options)
- [Chalice](../integrations/chalice.md#options)
- [Starlette](../integrations/starlette.md#options)

### Introspection

Introspection should primarily be used as a discovery and diagnostic tool for
testing and development, and should be disabled in production by default.

You can disable introspection by
[adding a validation rule extension](../extensions/add-validation-rules.md#more-examples).

## Security extensions

Strawberry provides some security extensions to limit various aspects of the
GraphQL document. These are recommended in production.

- [query depth](../extensions/query-depth-limiter.md)
- [max number of aliases](../extensions/max-aliases-limiter.md)
- [max number of tokens](../extensions/max-tokens-limiter.md)

# More resources

See the documentation for the integration you are using for more information on
deployment:

- [AIOHTTP](https://docs.aiohttp.org/en/stable/deployment.html)
- [Chalice](https://aws.github.io/chalice/quickstart.html#deploying)
- [Django](https://docs.djangoproject.com/en/4.0/howto/deployment/)
- [FastAPI](https://fastapi.tiangolo.com/deployment/)
- [Flask](https://flask.palletsprojects.com/en/2.0.x/deploying/)
- [Litestar](https://docs.litestar.dev/latest/topics/deployment/index.html)
- [Sanic](https://sanic.dev/en/guide/deployment/configuration.html)

The docs for [ASGI](https://asgi.readthedocs.io/en/latest/index.html) and
[Starlette](https://www.starlette.io/) do not provide an official deployment
guide, but you may find the documentation for other frameworks that use ASGI
servers useful (e.g. [FastAPI](https://fastapi.tiangolo.com/deployment/))

---

### Operations Testing (`docs/operations/testing.md`)

---
title: Testing
---

# Testing

The GraphiQL playground integrated with Strawberry available at
[http://localhost:8000/graphql](http://localhost:8000/graphql) (if you run the
schema with `strawberry dev`) can be a good place to start testing your queries
and mutations. However, at some point, while you are developing your application
(or even before if you are practising TDD), you may want to create some
automated tests.

We can use the Strawberry `schema` object we defined in the
[Getting Started tutorial](../index.md#step-5-create-our-schema-and-run-it) to
run our first test:

```python
import strawberry


@strawberry.type
class Book:
    title: str
    author: str


def get_books(title: str) -> list[Book]:
    if title == "The Great Gatsby":
        return [
            Book(
                title="The Great Gatsby",
                author="F. Scott Fitzgerald",
            ),
        ]
    return []


@strawberry.type
class Query:
    @strawberry.field
    def books(self, title: str) -> list[Book]:
        return get_books(title)


schema = strawberry.Schema(Query)


def test_query():
    query = """
        query TestQuery($title: String!) {
            books(title: $title) {
                title
                author
            }
        }
    """

    result = schema.execute_sync(
        query,
        variable_values={"title": "The Great Gatsby"},
    )

    assert result.errors is None
    assert result.data["books"] == [
        {
            "title": "The Great Gatsby",
            "author": "F. Scott Fitzgerald",
        }
    ]
```

This `test_query` example:

1. defines a complete schema with a `Book` type and a `books` query that accepts
   a `title` argument
2. defines the query we will test against, using a GraphQL variable `$title`
3. executes the query using `execute_sync`, passing the variable via
   `variable_values`
4. asserts that the result is what we are expecting: nothing in `errors` and our
   desired book in `data`

As you may have noticed, we explicitly defined the query variable `title`, and
we passed it separately with the `variable_values` argument, but we could have
directly hardcoded the `title` in the query string instead. We did this on
purpose because usually the query's arguments will be dynamic and, as we want to
test our application as close to production as possible, it wouldn't make much
sense to hardcode the variables in the query.

## Testing Async

Since Strawberry supports async, tests can also be written to be async:

```python
@pytest.mark.asyncio
async def test_query_async():
    ...

    resp = await schema.execute(query, variable_values={"title": "The Great Gatsby"})

    ...
```

## Testing Mutations

We can also write a test for our [`addBook` Mutation](../general/mutations.md)
example:

```python
@pytest.mark.asyncio
async def test_mutation():
    mutation = """
        mutation TestMutation($title: String!, $author: String!) {
            addBook(title: $title, author: $author) {
                title
            }
        }
    """

    resp = await schema.execute(
        mutation,
        variable_values={
            "title": "The Little Prince",
            "author": "Antoine de Saint-Exupéry",
        },
    )

    assert resp.errors is None
    assert resp.data["addBook"] == {
        "title": "The Little Prince",
    }
```

## Testing Subscriptions

And finally, a test for our [`count` Subscription](../general/subscriptions.md):

```python
import asyncio
import pytest
import strawberry


@strawberry.type
class Subscription:
    @strawberry.subscription
    async def count(self, target: int = 100) -> int:
        for i in range(target):
            yield i
            await asyncio.sleep(0.5)


@strawberry.type
class Query:
    @strawberry.field
    def hello() -> str:
        return "world"


schema = strawberry.Schema(query=Query, subscription=Subscription)


@pytest.mark.asyncio
async def test_subscription():
    query = """
    	subscription {
        	count(target: 3)
    	}
    """

    sub = await schema.subscribe(query)

    index = 0
    async for result in sub:
        assert not result.errors
        assert result.data == {"count": index}

        index += 1
```

As you can see testing Subscriptions is a bit more complicated because we want
to check the result of each individual result.

---

### Operations Tracing (`docs/operations/tracing.md`)

---
title: Tracing
---

# Tracing

## Apollo

To enable [Apollo tracing](https://github.com/apollographql/apollo-tracing) you
can use the ApolloTracingExtension provided:

```python
from strawberry.extensions.tracing import ApolloTracingExtension

schema = strawberry.Schema(query=Query, extensions=[ApolloTracingExtension])
```

Note that if you're not running under ASGI you'd need to use the sync version of
ApolloTracingExtension:

```python
from strawberry.extensions.tracing import ApolloTracingExtensionSync

schema = strawberry.Schema(query=Query, extensions=[ApolloTracingExtensionSync])
```

## Apollo Federation (FTV1)

For [Apollo Federation](https://www.apollographql.com/docs/federation/)
subgraphs, you can use the ApolloFederationTracingExtension to provide inline
tracing data. When a gateway sends the `apollo-federation-include-trace: ftv1`
header, the extension includes trace data in the response.

> **Security:** any client can send the `apollo-federation-include-trace: ftv1`
> header unless you restrict it. Tracing payloads expose resolver timing
> details, so make sure only a trusted Apollo Gateway (or other internal
> traffic) can request traces — for example by enforcing authentication, network
> policy, or stripping the header from public requests at the edge.

You need to install the extras for apollo-federation by doing:

```shell
pip install 'strawberry-graphql[apollo-federation]'
```

```python
from strawberry.extensions.tracing import ApolloFederationTracingExtension

schema = strawberry.Schema(query=Query, extensions=[ApolloFederationTracingExtension])
```

Note that if you're not running under ASGI you'd need to use the sync version of
ApolloFederationTracingExtension:

```python
from strawberry.extensions.tracing import ApolloFederationTracingExtensionSync

schema = strawberry.Schema(
    query=Query, extensions=[ApolloFederationTracingExtensionSync]
)
```

## Datadog

In addition to Apollo Tracing we also support tracing with
[Datadog](https://www.datadoghq.com/). using the DatadogTracingExtension.

```python
from strawberry.extensions.tracing import DatadogTracingExtension

schema = strawberry.Schema(query=Query, extensions=[DatadogTracingExtension])
```

Note that if you're not running under ASGI you'd need to use the sync version of
DatadogTracingExtension:

```python
from strawberry.extensions.tracing import DatadogTracingExtensionSync

schema = strawberry.Schema(query=Query, extensions=[DatadogTracingExtensionSync])
```

## Open Telemetry

In addition to Datadog and Apollo Tracing we also support
[opentelemetry](https://opentelemetry.io/), using the OpenTelemetryExtension.

You also need to install the extras for opentelemetry by doing:

```shell
pip install 'strawberry-graphql[opentelemetry]'
```

```python
from strawberry.extensions.tracing import OpenTelemetryExtension

schema = strawberry.Schema(query=Query, extensions=[OpenTelemetryExtension])
```

Note that if you're not running under ASGI you'd need to use the sync version of
OpenTelemetryExtension:

```python
from strawberry.extensions.tracing import OpenTelemetryExtensionSync

schema = strawberry.Schema(query=Query, extensions=[OpenTelemetryExtensionSync])
```

Example Elasticsearch, Kibana, APM, Collector docker-compose to track django and
strawberry tracing metrics

This will spin up:

- an elastic search instance to keep your data
- kibana to visualize data
- the elastic APM Server for processing incoming traces
- a
  [collector binding](https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-otlp)
  to transform the opentelemetry data (more exactly the Opentelementry Line
  Protocol OTLP) to something AMP can read
  ([our APM agent](https://github.com/open-telemetry/opentelemetry-collector))

For more details see the elasticsearch
[docs](https://www.elastic.co/guide/en/apm/get-started/current/open-telemetry-elastic.html)

```
/* Detailed source-code truncated for AI context efficiency. */
```

In the same directory add a `otel-collector-config.yaml`:

```yaml
receivers:
  otlp:
    protocols:
      grpc:

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 2000
  batch:

exporters:
  logging:
    loglevel: warn
  otlp/elastic:
    endpoint: "apm-server:8200"
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [logging, otlp/elastic]
      processors: [batch]
    metrics:
      receivers: [otlp]
      exporters: [logging, otlp/elastic]
      processors: [batch]
```

Spin this docker-compose up with (this will take a while, give it a minute):

```shell
docker-compose up --force-recreate --build
```

Example Django Integration

Requirements:

```shell
pip install opentelemetry-api
pip install opentelemetry-sdk
pip install opentelemetry-exporter-otlp
```

in the manage.py

```python
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

resource = Resource(attributes={"service.name": "yourservicename"})
trace.set_tracer_provider(TracerProvider(resource=resource))
tracer = trace.get_tracer(__name__)
otlp_exporter = OTLPSpanExporter(endpoint="http://localhost:4317", insecure=True)
span_processor = BatchSpanProcessor(otlp_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)

...


def main():
    DjangoInstrumentor().instrument()
    ...
```

---

### Types Defer And Stream (`docs/types/defer-and-stream.md`)

---
title: Defer and Stream
---

# Defer and Stream

Strawberry provides experimental support for GraphQL's `@defer` and `@stream`
directives, which enable incremental delivery of response data. These directives
allow parts of a GraphQL response to be delivered as they become available,
rather than waiting for the entire response to be ready.

<Note>

This feature is currently experimental. The API and behavior may change in
future releases.

**Important limitations:**

- Extensions (most importantly `MaskErrors`) are not fully supported yet.
  Extensions currently only process the initial result and do not handle
  incremental payloads delivered by `@defer` and `@stream`.
- This means error masking and other extension functionality will only apply to
  the initial response, not to deferred or streamed data.
- Incremental delivery requires asynchronous execution. `Schema.execute_sync`
  and the synchronous integrations (such as the sync Django, Flask and Chalice
  views) return an error for operations that use `@defer` or `@stream`.

</Note>

## Enabling Defer and Stream

To use `@defer` and `@stream` directives, you need to enable experimental
incremental execution in your schema configuration:

```python
import strawberry
from strawberry.schema.config import StrawberryConfig


@strawberry.type
class Query:
    # Your query fields here
    pass


schema = strawberry.Schema(
    query=Query, config=StrawberryConfig(enable_experimental_incremental_execution=True)
)
```

## Using @defer

The `@defer` directive allows you to mark parts of a query to be resolved
asynchronously. The initial response will include all non-deferred fields,
followed by incremental payloads containing the deferred data.

### Example

```python
import asyncio
import strawberry


@strawberry.type
class Author:
    id: strawberry.ID
    name: str
    bio: str


@strawberry.type
class Article:
    id: strawberry.ID
    title: str
    content: str

    @strawberry.field
    async def author(self) -> Author:
        # Simulate an expensive operation
        await asyncio.sleep(2)
        return Author(
            id=strawberry.ID("1"),
            name="Jane Doe",
            bio="A passionate writer and developer.",
        )


@strawberry.type
class Query:
    @strawberry.field
    async def article(self, id: strawberry.ID) -> Article:
        return Article(
            id=id,
            title="Introduction to GraphQL Defer",
            content="Learn how to use the @defer directive...",
        )
```

With this schema, you can query with `@defer`:

```graphql
query GetArticle {
  article(id: "123") {
    id
    title
    content
    ... on Article @defer {
      author {
        id
        name
        bio
      }
    }
  }
}
```

The response will be delivered incrementally:

```json
# Initial payload
{
  "data": {
    "article": {
      "id": "123",
      "title": "Introduction to GraphQL Defer",
      "content": "Learn how to use the @defer directive..."
    }
  },
  "hasNext": true
}

# Subsequent payload
{
  "incremental": [{
    "data": {
      "author": {
        "id": "1",
        "name": "Jane Doe",
        "bio": "A passionate writer and developer."
      }
    },
    "path": ["article"]
  }],
  "hasNext": false
}
```

## Using @stream with strawberry.Streamable

The `@stream` directive works with list fields and allows items to be delivered
as they become available. Strawberry provides a special `Streamable` type
annotation for fields that can be streamed.

### Example

```python
import asyncio
import strawberry
from typing import AsyncGenerator


@strawberry.type
class Comment:
    id: strawberry.ID
    content: str
    author_name: str


@strawberry.type
class BlogPost:
    id: strawberry.ID
    title: str

    @strawberry.field
    async def comments(self) -> strawberry.Streamable[Comment]:
        """Stream comments as they are fetched from the database."""
        for i in range(5):
            # Simulate fetching comments from a database
            await asyncio.sleep(0.5)
            yield Comment(
                id=strawberry.ID(f"comment-{i}"),
                content=f"This is comment number {i}",
                author_name=f"User {i}",
            )
```

Query with `@stream`:

```graphql
query GetBlogPost {
  blogPost(id: "456") {
    id
    title
    comments @stream(initialCount: 2) {
      id
      content
      authorName
    }
  }
}
```

The response will stream the comments:

```json
# Initial payload with first 2 comments
{
  "data": {
    "blogPost": {
      "id": "456",
      "title": "My Blog Post",
      "comments": [
        {
          "id": "comment-0",
          "content": "This is comment number 0",
          "authorName": "User 0"
        },
        {
          "id": "comment-1",
          "content": "This is comment number 1",
          "authorName": "User 1"
        }
      ]
    }
  },
  "hasNext": true
}

# Subsequent payloads for remaining comments
{
  "incremental": [{
    "items": [{
      "id": "comment-2",
      "content": "This is comment number 2",
      "authorName": "User 2"
    }],
    "path": ["blogPost", "comments", 2]
  }],
  "hasNext": true
}
# ... more incremental payloads
```

---

### Types Enums (`docs/types/enums.md`)

---
title: Enums
---

# Enums

Enums are a special kind of type that is restricted to a particular set of
values.

For example, we have a few options of ice cream available, and we want to allow
user to choose only from those options.

Strawberry supports defining enums using enums from python's standard library.
Here's a quick tutorial on how to create an enum type in Strawberry:

First, create a new class for the new type, which extends class Enum:

```python
from enum import Enum


class IceCreamFlavour(Enum): ...
```

Then, list options as variables in that class:

```python
class IceCreamFlavour(Enum):
    VANILLA = "vanilla"
    STRAWBERRY = "strawberry"
    CHOCOLATE = "chocolate"
```

Finally we need to register our class as a strawberry type. It's done with the
`strawberry.enum` decorator:

```python
@strawberry.enum
class IceCreamFlavour(Enum):
    VANILLA = "vanilla"
    STRAWBERRY = "strawberry"
    CHOCOLATE = "chocolate"
```

<Note>

In some cases you already have an enum defined elsewhere in your code. You can
safely use it in your schema and strawberry will generate a default graphql
implementation of it.

The only drawback is that it is not currently possible to configure it
(documentation / renaming or using `strawberry.enum_value` on it).

</Note>

Let's see how we can use Enums in our schema.

```python
@strawberry.type
class Query:
    @strawberry.field
    def best_flavour(self) -> IceCreamFlavour:
        return IceCreamFlavour.STRAWBERRY
```

Defining the enum type above would produce this schema in GraphQL:

```graphql
enum IceCreamFlavour {
  VANILLA
  STRAWBERRY
  CHOCOLATE
}
```

Here's an example of how you'd use this newly created query:

```graphql
query {
  bestFlavour
}
```

Here is result of executed query:

```graphql
{
  "data": {
    "bestFlavour": "STRAWBERRY"
  }
}
```

We can also use enums when defining object types (using `strawberry.type`). Here
is an example of an object that has a field using an Enum:

```python
@strawberry.type
class Cone:
    flavour: IceCreamFlavour
    num_scoops: int


@strawberry.type
class Query:
    @strawberry.field
    def cone(self) -> Cone:
        return Cone(flavour=IceCreamFlavour.STRAWBERRY, num_scoops=4)
```

And here's an example of how you'd use this query:

```graphql
query {
  cone {
    flavour
    numScoops
  }
}
```

Here is result of executed query:

```graphql
{
  "data": {
    "cone": {
      "flavour": "STRAWBERRY",
      "numScoops": 4
    }
  }
}
```

<Note>

GraphQL types are not a map of name: value, like in python enums. Strawberry
defaults to using the name of the members of the enum to create the GraphQL
type. You can use their values instead with
`@strawberry.enum(graphql_name_from="value")`

</Note>

You can also deprecate enum value. To do so you need more verbose syntax using
`strawberry.enum_value` and `deprecation_reason`. You can mix and match string
and verbose syntax.

```python
@strawberry.enum
class IceCreamFlavour(Enum):
    VANILLA = strawberry.enum_value("vanilla")
    CHOCOLATE = "chocolate"
    STRAWBERRY = strawberry.enum_value(
        "strawberry", deprecation_reason="Let's call the whole thing off"
    )
```

You can also give custom names to enum values in the GraphQL schema using the
`name` parameter:

```python
@strawberry.enum
class IceCreamFlavour(Enum):
    VANILLA = "vanilla"
    CHOCOLATE_COOKIE = strawberry.enum_value("chocolate", name="chocolateCookie")
```

This will produce the following GraphQL schema:

```graphql
enum IceCreamFlavour {
  VANILLA
  chocolateCookie
}
```

When querying, the custom name will be used in the response:

```graphql
{
  "data": {
    "bestFlavour": "chocolateCookie"
  }
}
```

Note that the Python enum member name (`CHOCOLATE_COOKIE`) is still used in your
Python code, while the custom name (`chocolateCookie`) is used in the GraphQL
schema and responses.

---

### Types Exceptions (`docs/types/exceptions.md`)

---
title: Exceptions
toc: true
---

# Strawberry Exceptions

Strawberry defines its library-specific exceptions in `strawberry.exceptions`.

## Strawberry Schema Exceptions

### FieldWithResolverAndDefaultFactoryError

This exception is raised when `strawberry.field` is used with both `resolver`
and `default_factory` arguments.

```python
@strawberry.type
class Query:
    @strawberry.field(default_factory=lambda: "Example C")
    def c(self) -> str:
        return "I'm a resolver"


# Throws 'Field "c" on type "Query" cannot define a default_factory and a resolver.'
```

### FieldWithResolverAndDefaultValueError

This exception is raised when `strawberry.field` is used with both `resolver`
and `default` arguments.

```python
def test_resolver() -> str:
    return "I'm a resolver"


@strawberry.type
class Query:
    c: str = strawberry.field(default="Example C", resolver=test_resolver)


# Throws 'Field "c" on type "Query" cannot define a default value and a resolver.'
```

### MissingTypesForGenericError

This exception is raised when a `Generic` type is added to the Strawberry Schema
without passing any type to make it concrete.

### MultipleStrawberryArgumentsError

This exception is raised when `strawberry.argument` is used multiple times in a
type annotation.

```python
import strawberry
from typing_extensions import Annotated


@strawberry.field
def name(
    argument: Annotated[
        str,
        strawberry.argument(description="This is a description"),
        strawberry.argument(description="Another description"),
    ],
) -> str:
    return "Name"


# Throws 'Annotation for argument `argument` on field `name` cannot have multiple `strawberry.argument`s'
```

### UnsupportedTypeError

This exception is thrown when the type-annotation used is not supported by
`strawberry.field`. At the time of writing this exception is used by Pydantic
only

```python
class Model(pydantic.BaseModel):
    field: pydantic.Json


@strawberry.experimental.pydantic.type(Model)
class Type:
    field: strawberry.auto
```

### WrongNumberOfResultsReturned

This exception is raised when the DataLoader returns a different number of
results than requested.

```python
async def idx(keys):
    return [1, 2]


loader = DataLoader(load_fn=idx)

await loader.load(1)

# Throws 'Received wrong number of results in dataloader, expected: 1, received: 2'
```

## Runtime exceptions

Some errors are also thrown when trying to exectuing queries (mutations or
subscriptions).

### MissingQueryError

This exception is raised when the `request` is missing the `query` parameter.

```python
client.post("/graphql", data={})

# Throws 'Request data is missing a "query" value'
```

## UnallowedReturnTypeForUnion

This error is raised when the return type of a `Union` is not in the list of
Union types.

```python
@strawberry.type
class Outside:
    c: int


@strawberry.type
class A:
    a: int


@strawberry.type
class B:
    b: int


@strawberry.type
class Mutation:
    @strawberry.mutation
    def hello(self) -> Union[A, B]:
        return Outside(c=5)


query = """
    mutation {
        hello {
            __typename

            ... on A {
                a
            }

            ... on B {
                b
            }
        }
    }
"""

result = schema.execute_sync(query)
# result will look like:
# ExecutionResult(
#     data=None,
#     errors=[
#         GraphQLError(
#             "The type \"<class 'schema.Outside'>\" of the field \"hello\" is not in the list of the types of the union: \"['A', 'B']\"",
#             locations=[SourceLocation(line=3, column=9)],
#             path=["hello"],
#         )
#     ],
#     extensions={},
# )
```

## WrongReturnTypeForUnion

This exception is thrown when the Union type cannot be resolved because it's not
a `strawberry.field`.

```python
@strawberry.type
class A:
    a: int


@strawberry.type
class B:
    b: int


@strawberry.type
class Query:
    ab: Union[A, B] = "ciao"  # missing `strawberry.field` !


query = """{
    ab {
        __typename,

        ... on A {
            a
        }
    }
}"""

result = schema.execute_sync(query, root_value=Query())

# result will look like:
# ExecutionResult(
#     data=None,
#     errors=[
#         GraphQLError(
#             'The type "<class \'str\'>" cannot be resolved for the field "ab" , are you using a strawberry.field?',
#             locations=[SourceLocation(line=2, column=9)],
#             path=["ab"],
#         )
#     ],
#     extensions={},
# )
```

---

### Types Generics (`docs/types/generics.md`)

---
title: Generics
---

# Generics

Strawberry supports using Python's `Generic` typing to dynamically create
reusable types.

Strawberry will automatically generate the correct GraphQL schema from the
combination of the generic type and the type arguments. Generics are supported
in Object types, Input types, and Arguments to queries, mutations, and scalars.

Let's take a look at an example:

# Object Types

```python
from typing import Generic, List, TypeVar

import strawberry

T = TypeVar("T")


@strawberry.type
class Page(Generic[T]):
    number: int
    items: List[T]
```

This example defines a generic type `Page` that can be used to represent a page
of any type. For example, we can create a page of `User` objects:

<CodeGrid>

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type
class Query:
    users: Page[User]
```

```graphql
type Query {
  users: UserPage!
}

type User {
  name: String!
}

type UserPage {
  number: Int!
  items: [User!]!
}
```

</CodeGrid>

It is also possible to use a specialized generic type directly. For example, the
same example above could be written like this:

<CodeGrid>

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type
class UserPage(Page[User]): ...


@strawberry.type
class Query:
    users: UserPage
```

```graphql
type Query {
  users: UserPage!
}

type User {
  name: String!
}

type UserPage {
  number: Int!
  items: [User!]!
}
```

</CodeGrid>

# Input and Argument Types

Arguments to queries and mutations can also be made generic by creating Generic
Input types. Here we'll define an input type that can serve as a collection of
anything, then create a specialization by using as a filled-in argument on a
mutation.

<CodeGrid>

```python
import strawberry
from typing import Generic, List, Optional, TypeVar

T = TypeVar("T")


@strawberry.input
class CollectionInput(Generic[T]):
    values: List[T]


@strawberry.input
class PostInput:
    name: str


@strawberry.type
class Post:
    id: int
    name: str


@strawberry.type
class Mutation:
    @strawberry.mutation
    def add_posts(self, posts: CollectionInput[PostInput]) -> bool:
        return True


@strawberry.type
class Query:
    most_recent_post: Optional[Post] = None


schema = strawberry.Schema(query=Query, mutation=Mutation)
```

```graphql
input PostInputCollectionInput {
  values: [PostInput!]!
}

input PostInput {
  name: String!
}

type Post {
  id: Int!
  name: String!
}

type Query {
  mostRecentPost: Post
}

type Mutation {
  addPosts(posts: PostInputCollectionInput!): Boolean!
}
```

</CodeGrid>

> **Note**: Pay attention to the fact that both `CollectionInput` and
> `PostInput` are Input types. Providing `posts: CollectionInput[Post]` to
> `add_posts` (i.e. using the non-input `Post` type) would have resulted in an
> error:
>
> ```
> PostCollectionInput fields cannot be resolved. Input field type must be a
> GraphQL input type
> ```

# Multiple Specializations

Using multiple specializations of a Generic type will work as expected. Here we
define a `Point2D` type and then specialize it for both `int`s and `float`s.

<CodeGrid>

```python
from typing import Generic, TypeVar

import strawberry

T = TypeVar("T")


@strawberry.input
class Point2D(Generic[T]):
    x: T
    y: T


@strawberry.type
class Mutation:
    @strawberry.mutation
    def store_line_float(self, a: Point2D[float], b: Point2D[float]) -> bool:
        return True

    @strawberry.mutation
    def store_line_int(self, a: Point2D[int], b: Point2D[int]) -> bool:
        return True
```

```graphql
type Mutation {
  storeLineFloat(a: FloatPoint2D!, b: FloatPoint2D!): Boolean!
  storeLineInt(a: IntPoint2D!, b: IntPoint2D!): Boolean!
}

input FloatPoint2D {
  x: Float!
  y: Float!
}

input IntPoint2D {
  x: Int!
  y: Int!
}
```

</CodeGrid>

# Variadic Generics

Variadic Generics, introduced in [PEP-646][pep-646], are currently unsupported.

[pep-646]: https://peps.python.org/pep-0646/

---

### Types Input Types (`docs/types/input-types.md`)

---
title: Input types
---

# Input types

In addition to [object types](./object-types) GraphQL also supports input types.
While being similar to object types, they are better suited for input data as
they limit the kind of types you can use for fields.

This is how the
[GraphQL spec defines the difference between object types and input types](https://spec.graphql.org/June2018/#sec-Input-Objects):

> The GraphQL Object type (ObjectTypeDefinition)... is inappropriate for re‐use
> (as input), because Object types can contain fields that define arguments or
> contain references to interfaces and unions, neither of which is appropriate
> for use as an input argument. For this reason, input objects have a separate
> type in the system.

## Defining input types

In Strawberry, you can define input types by using the `@strawberry.input`
decorator, like this:

<CodeGrid>

```python
import strawberry


@strawberry.input
class Point2D:
    x: float
    y: float
```

```graphql
input Point2D {
  x: Float!
  y: Float!
}
```

</CodeGrid>

Then you can use input types as argument for your fields or mutations:

```python
import strawberry


@strawberry.type
class Mutation:
    @strawberry.mutation
    def store_point(self, a: Point2D) -> bool:
        return True
```

If you want to include optional arguments, you need to provide them with a
default. For example if we want to expand on the above example to allow optional
labeling of our point we could do:

<CodeGrid>

```python
import strawberry
from typing import Optional


@strawberry.input
class Point2D:
    x: float
    y: float
    label: Optional[str] = None
```

```graphql
type Point2D {
    x: Float!
    y: Float!
    label: String = null
}
```

</CodeGrid>

When you need to distinguish between a field being set to `null` versus being
completely absent (common in update operations), you can use `strawberry.Maybe`.
See the [Maybe documentation](./maybe.md) for comprehensive examples and usage
patterns.

Input types only hold the values sent by the client, so their fields can't have
resolvers. Strawberry raises an error when an input type has a field with a
resolver, including one inherited from an output type.

## Input instances as default values

An input type instance can be used as the default value of a resolver argument
or of another input's field. The default is printed in the schema, reported by
introspection, and each execution receives a fresh instance:

<CodeGrid>

```python
import strawberry


@strawberry.input
class Pagination:
    limit: int = 10
    offset: int = 0


@strawberry.input
class Filters:
    query: str
    pagination: Pagination = strawberry.field(default_factory=Pagination)


@strawberry.type
class Query:
    @strawberry.field
    def search(self, filters: Filters = Filters(query="")) -> list[str]:
        return []
```

```graphql
input Pagination {
  limit: Int! = 10
  offset: Int! = 0
}

input Filters {
  query: String!
  pagination: Pagination! = { limit: 10, offset: 0 }
}

type Query {
  search(
    filters: Filters! = { query: "", pagination: { limit: 10, offset: 0 } }
  ): [String!]!
}
```

</CodeGrid>

## API

`@strawberry.input(name: str = None, description: str = None)`

Creates an input type from a class definition.

- `name`: if set this will be the GraphQL name, otherwise the GraphQL will be
  generated by camel-casing the name of the class.
- `description`: this is the GraphQL description that will be returned when
  introspecting the schema or when navigating the schema using GraphiQL.

## One Of Input Types

Strawberry also supports defining input types that can have only one field set.
This is based on the
[OneOf Input Objects RFC](https://github.com/graphql/graphql-spec/pull/825)

To define a one of input type you can use the `one_of` flag on the
`@strawberry.input` decorator:

<CodeGrid>

```python
import strawberry


@strawberry.input(one_of=True)
class SearchBy:
    name: str | None
    email: str | None
```

```graphql
input SearchBy @oneOf {
  name: String
  email: String
}
```

</CodeGrid>

Clients set exactly one field, which can't be `null`, and Strawberry sets the
other fields to `None`.

<Note>

GraphQL requires the fields of a OneOf input to be nullable and without a
default value, so Strawberry raises an error when the schema is built if one of
them is required or has a default, like `name: str | None = None`.

Fields declared with `strawberry.Maybe` work too, but as OneOf fields can't be
set to `null`, the `Some` wrapper doesn't add anything here.

</Note>

## Deprecating fields

Fields can be deprecated using the argument `deprecation_reason`.

<Note>

This does not prevent the field from being used, it's only for documentation.
See:
[GraphQL field deprecation](https://spec.graphql.org/June2018/#sec-Field-Deprecation).

</Note>

<CodeGrid>

```python
import strawberry
from typing import Optional


@strawberry.input
class Point2D:
    x: float
    y: float
    z: Optional[float] = strawberry.field(
        deprecation_reason="3D coordinates are deprecated"
    )
    label: Optional[str] = None
```

```graphql
input Point2D {
  x: Float!
  y: Float!
  z: Float @deprecated(reason: "3D coordinates are deprecated")
  label: String = null
}
```

</CodeGrid>

---

### Types Interfaces (`docs/types/interfaces.md`)

---
title: Interfaces
---

# Interfaces

Interfaces are an abstract type which may be implemented by object types.

An interface has fields, but it’s never instantiated. Instead, objects may
implement interfaces, which makes them a member of that interface. Also, fields
may return interface types. When this happens, the returned object may be any
member of that interface.

For example, let's say a `Customer` (interface) can either be an `Individual`
(object) or a `Company` (object). Here's what that might look like in the
[GraphQL Schema Definition Language](https://graphql.org/learn/schema/#type-language)
(SDL):

```graphql
interface Customer {
  name: String!
}

type Company implements Customer {
  employees: [Individual!]!
  name: String!
}

type Individual implements Customer {
  employed_by: Company
  name: String!
}

type Query {
  customers: [Customer!]!
}
```

Notice that the `Customer` interface requires the `name: String!` field. Both
`Company` and `Individual` implement that field so that they can satisfy the
`Customer` interface.

When querying, you can select the fields on an interface:

```graphql
query {
  customers {
    name
  }
}
```

Whether the object is a `Company` or an `Individual`, it doesn’t matter – you
still get their name. If you want some object-specific fields, you can query
them with an
[inline fragment](https://graphql.org/learn/queries/#inline-fragments), for
example:

```graphql
query {
  customers {
    name
    ... on Individual {
      company {
        name
      }
    }
  }
}
```

Interfaces are a good choice whenever you have a set of objects that are used
interchangeably, and they have several significant fields in common. When they
don’t have fields in common, use a [Union](/docs/types/union) instead.

## Defining interfaces

Interfaces are defined using the `@strawberry.interface` decorator:

<CodeGrid>

```python
import strawberry


@strawberry.interface
class Customer:
    name: str
```

```graphql
interface Customer {
  name: String!
}
```

</CodeGrid>

<Note>

Interface classes should never be instantiated directly.

</Note>

## Implementing interfaces

To define an object type that implements an interface, the type must inherit
from the interface:

```python
import strawberry


@strawberry.type
class Individual(Customer):
    # additional fields
    ...


@strawberry.type
class Company(Customer):
    # additional fields
    ...
```

<Tip>

If you add an object type which implements an interface, but that object type
doesn’t appear in your schema as a field return type or a union member, then you
will need to add that object to the Schema definition directly.

```python
schema = strawberry.Schema(query=Query, types=[Individual, Company])
```

</Tip>

Interfaces can also implement other interfaces:

<CodeGrid>

```python
import strawberry


@strawberry.interface
class Error:
    message: str


@strawberry.interface
class FieldError(Error):
    message: str
    field: str


@strawberry.type
class PasswordTooShort(FieldError):
    message: str
    field: str
    min_length: int
```

```graphql
interface Error {
  message: String!
}

interface FieldError implements Error {
  message: String!
  field: String!
}

type PasswordTooShort implements FieldError & Error {
  message: String!
  field: String!
  minLength: Int!
}
```

</CodeGrid>

## Implementing fields

Interfaces can provide field implementations as well. For example:

```python
import strawberry


@strawberry.interface
class Customer:
    @strawberry.field
    def name(self) -> str:
        return self.name.title()
```

This resolve method will be called by objects who implement the interface.
Object classes can override the implementation by defining their own `name`
field:

```python
import strawberry


@strawberry.type
class Company(Customer):
    @strawberry.field
    def name(self) -> str:
        return f"{self.name} Limited"
```

## Resolving an interface

When a field’s return type is an interface, GraphQL needs to know what specific
object type to use for the return value. In the example above, each customer
must be categorized as an `Individual` or `Company`. To do this you need to
always return an instance of an object type from your resolver:

```python
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def best_customer(self) -> Customer:
        return Individual(name="Patrick")
```

---

### Types Lazy (`docs/types/lazy.md`)

---
title: Lazy Types
---

# Lazy Types

Strawberry supports lazy types, which are useful when you have circular
dependencies between types.

For example, let's say we have a `User` type that has a list of `Post` types,
and each `Post` type has a `User` field. In this case, we can't define the
`User` type before the `Post` type, and vice versa.

To solve this, we can use lazy types:

```python
# posts.py
from typing import TYPE_CHECKING, Annotated

import strawberry

if TYPE_CHECKING:
    from .users import User


@strawberry.type
class Post:
    title: str
    author: Annotated["User", strawberry.lazy(".users")]
```

```python
# users.py
from typing import TYPE_CHECKING, Annotated, List

import strawberry

if TYPE_CHECKING:
    from .posts import Post


@strawberry.type
class User:
    name: str
    posts: List[Annotated["Post", strawberry.lazy(".posts")]]
```

`strawberry.lazy` in combination with `Annotated` allows us to define the path
of the module of the type we want to use, this allows us to leverage Python's
type hints, while preventing circular imports and preserving type safety by
using `TYPE_CHECKING` to tell type checkers where to look for the type.

## Python 3.15 lazy imports

On Python 3.15+, `strawberry.lazy` can reference a module that re-exports a type
using Python's native lazy imports:

```python
# exported_types.py (Python 3.15+)
lazy from .users import User
```

Use `Annotated["User", strawberry.lazy(".exported_types")]` to reference this
re-export. Strawberry resolves the native lazy import when it needs the type to
build the schema. This also works for imports made lazy through
`__lazy_modules__`.

---

### Types Maybe (`docs/types/maybe.md`)

---
title: Maybe
---

# Maybe

In GraphQL, there's an important distinction between a field that is `null` and
a field that is completely absent from the input. Strawberry's `Maybe` type
allows you to differentiate between these states:

<Note>

`Maybe` is the recommended way to handle optional input fields in Strawberry. If
you're using `strawberry.UNSET` for this purpose, we encourage migrating to
`Maybe` for better type safety and clearer semantics. See
[Migrating from UNSET](#migrating-from-unset) for details.

</Note>

For `Maybe[str]`:

1. **Field present with a value**: `Some("hello")`
2. **Field completely absent**: `None`

For `Maybe[str | None]` (when you need to handle explicit nulls):

1. **Field present with a value**: `Some("hello")`
2. **Field present but explicitly null**: `Some(None)`
3. **Field completely absent**: `None`

This is particularly useful for update operations where you need to distinguish
between "set this field to null" and "don't change this field at all".

The design is inspired by Rust's
[`Option<T>`](https://doc.rust-lang.org/std/option/) type and similar patterns
in functional programming languages like Haskell's `Maybe` and Scala's `Option`.

## What problem does `strawberry.Maybe` solve?

Consider this common scenario: you have a user profile with an optional phone
number, and you want to provide an update mutation. With traditional nullable
types, you can't distinguish between:

- "Set the phone number to null" (remove the phone number)
- "Don't change the phone number" (leave it as is)

Both would be represented as `phone: null` in your GraphQL mutation.

## Basic Usage

Here's how to use `Maybe` in your Strawberry schema:

```python
import strawberry


@strawberry.input
class UpdateUserInput:
    name: str | None = None  # Traditional optional field
    phone: strawberry.Maybe[str | None]  # Maybe field


@strawberry.type
class User:
    name: str
    phone: str | None


@strawberry.type
class Mutation:
    @strawberry.mutation
    def update_user(self, user_id: str, input: UpdateUserInput) -> User:
        user = get_user(user_id)  # Your user retrieval logic

        # Traditional optional field - only update if provided
        if input.name is not None:
            user.name = input.name

        # Maybe field - check if field was provided at all
        if input.phone is not None:  # Field was provided
            user.phone = input.phone.value  # Access the actual value
        # If input.phone is None, the field wasn't provided - no change

        return user
```

## Understanding Some()

When a `Maybe` field has a value (including `null`), it's wrapped in a `Some()`
container:

```python
# Field provided with a string value
phone = strawberry.Some("555-1234")
print(phone.value)  # "555-1234"

# Field provided with null value
phone = strawberry.Some(None)
print(phone.value)  # None

# Field not provided at all
phone = None
print(phone)  # None
```

## GraphQL Schema

When you use `Maybe` in your schema, it appears as a nullable field in GraphQL:

```python
@strawberry.input
class UpdateUserInput:
    phone: strawberry.Maybe[str | None]
```

Generates this GraphQL schema:

```graphql
input UpdateUserInput {
  phone: String
}
```

## Common Patterns

### Input Types for Updates

`Maybe` is most commonly used in input types for update operations:

```python
@strawberry.input
class UpdatePostInput:
    # Maybe[T] - value or absent, null is INVALID
    # Use when the field must have a value if provided
    title: strawberry.Maybe[str]
    content: strawberry.Maybe[str]
    published: strawberry.Maybe[bool]

    # Maybe[T | None] - value, null, or absent
    # Use when null is a valid value (e.g., to clear/remove the field)
    tags: strawberry.Maybe[list[str] | None]


@strawberry.type
class Mutation:
    @strawberry.mutation
    def update_post(self, post_id: str, input: UpdatePostInput) -> Post:
        post = get_post(post_id)

        # Only update fields that were explicitly provided
        if input.title is not None:
            post.title = input.title.value
        if input.content is not None:
            post.content = input.content.value
        if input.published is not None:
            post.published = input.published.value
        if input.tags is not None:
            post.tags = input.tags.value  # Could be None to clear tags

        return post
```

## Maybe vs Optional vs Nullable

The key distinction is between `Maybe[T]` and `Maybe[T | None]`:

- **`Maybe[T]`**: Two states - value provided or absent. Use when the field
  cannot be set to null (e.g., a required `title` that you either update or
  leave unchanged).
- **`Maybe[T | None]`**: Three states - value provided, null provided, or
  absent. Use when null is meaningful (e.g., clearing an optional `phone`
  number).

<Note>

Both `Maybe[T]` and `Maybe[T | None]` generate the same GraphQL schema (a
nullable field). The distinction between them is enforced by Strawberry's
internal validation, not by the GraphQL spec. When a client sends `null` to a
`Maybe[T]` field, Strawberry returns a validation error before the resolver is
called.

</Note>

Full comparison:

| Type                            | Python     | GraphQL   | Absent   | Null          | Value          |
| ------------------------------- | ---------- | --------- | -------- | ------------- | -------------- |
| `str`                           | Required   | `String!` | ❌ Error | ❌ Error      | ✅ Value       |
| `str \| None`                   | Optional   | `String`  | ✅ None  | ✅ None       | ✅ Value       |
| `strawberry.Maybe[str]`         | Maybe      | `String`  | ✅ None  | ❌ Error      | ✅ Some(value) |
| `strawberry.Maybe[str \| None]` | Maybe+Null | `String`  | ✅ None  | ✅ Some(None) | ✅ Some(value) |

## Best Practices

### When to Use Maybe

Use `Maybe` when you need to distinguish between:

- Field not provided (no change)
- Field provided with null (clear/remove)
- Field provided with value (set/update)

Common use cases:

- Update mutations
- Patch operations
- Optional filters that need to distinguish between "not filtering" and
  "filtering by null"

### When to Use Optional Instead

Use regular optional types (`str | None`) when:

- You only need two states: value or null
- The field absence and null have the same meaning
- You're defining output types (GraphQL responses)

### Error Handling

Always check if a `Maybe` field was provided before accessing its value:

```python
# Good
if input.phone is not None:
    user.phone = input.phone.value

# Bad - will raise AttributeError if phone is None
user.phone = input.phone.value
```

### Helper Functions

You can create helper functions to make Maybe handling cleaner:

```python
def update_if_provided(obj, field_name: str, maybe_value):
    """Update object field only if Maybe value was provided."""
    if maybe_value is not None:
        setattr(obj, field_name, maybe_value.value)


# Usage
update_if_provided(user, "phone", input.phone)
update_if_provided(user, "email", input.email)
```

## Migrating from UNSET

If you're currently using `strawberry.UNSET` to differentiate between absent and
null values, we recommend migrating to `Maybe` for better type safety and
clearer semantics.

### Why Migrate?

`Maybe` provides advantages over `UNSET`:

1. **Type Safety**: `Maybe[T]` is a proper generic type that works correctly
   with type checkers, whereas `UNSET` is typed as `Any` which defeats static
   analysis
2. **Explicit Nullability**: With `UNSET`, you write `field: str | None = UNSET`
   where it's ambiguous whether `None` is a valid value or represents "absent".
   With `Maybe`, `Maybe[str]` means null is invalid, while `Maybe[str | None]`
   explicitly allows null as a value

### Migration Example

Before (using UNSET):

```python
import strawberry


@strawberry.input
class UpdateUserInput:
    name: str | None = strawberry.UNSET
    phone: str | None = strawberry.UNSET


@strawberry.type
class Mutation:
    @strawberry.mutation
    def update_user(self, input: UpdateUserInput) -> User:
        if input.name is not strawberry.UNSET:
            user.name = input.name  # Could be a string or None
        if input.phone is not strawberry.UNSET:
            user.phone = input.phone
        return user
```

After (using Maybe):

```python
import strawberry


@strawberry.input
class UpdateUserInput:
    name: strawberry.Maybe[str | None]
    phone: strawberry.Maybe[str | None]


@strawberry.type
class Mutation:
    @strawberry.mutation
    def update_user(self, input: UpdateUserInput) -> User:
        if input.name is not None:
            user.name = input.name.value  # Access via .value
        if input.phone is not None:
            user.phone = input.phone.value
        return user
```

### Key Differences

| Aspect          | UNSET                       | Maybe                            |
| --------------- | --------------------------- | -------------------------------- |
| Check absent    | `value is strawberry.UNSET` | `value is None`                  |
| Access value    | `value` (direct)            | `value.value` (via Some)         |
| Type annotation | `T \| None = UNSET`         | `Maybe[T]` or `Maybe[T \| None]` |
| Null handling   | Implicit                    | Explicit with `T \| None`        |

### Codemod

If you have existing `Maybe[T]` annotations that need to accept explicit null
values, Strawberry provides a codemod to convert them to `Maybe[T | None]`:

```bash
python -m libcst.tool codemod strawberry.codemods.maybe_optional.ConvertMaybeToOptional .
```

Note: This codemod is for updating `Maybe` annotations, not for migrating from
`UNSET` to `Maybe`. Migration from `UNSET` requires manual changes to update
both the type annotations and the value access patterns (from `value` to
`value.value`).

## Related Types

- [Input Types](./input-types.md) - Using Maybe in input type definitions
- [Resolvers](./resolvers.md) - Using Maybe in resolver arguments
- [Union Types](./union.md) - Combining Maybe with union types
- [Scalars](./scalars.md) - Custom scalar types with Maybe

---

### Types Object Types (`docs/types/object-types.md`)

---
title: Object types
---

# Object types

Object types are the fundamentals of any GraphQL schema, they are used to define
the kind of objects that exist in a schema. Object types are created by defining
a name and a list of fields, here’s an example object type defined using the
GraphQL schema language:

```graphql
type Character {
  name: String!
  age: Int!
}
```

## A note on Query, Mutation and Subscription

While reading about GraphQL you might have encountered 3 special object types:
`Query`, `Mutation` and `Subscription`. They are defined as standard object
types, with the difference that they are also used as entry points for your
schema (also referred as root types).

- `Query` is the entry point for all the query operations
- `Mutation` is the entry point for all the mutations
- `Subscription` is the entry point for all the subscriptions.

For a walk-through on how to define schemas, read the
[schema basics](../general/schema-basics.md).

## Defining object types

In Strawberry, you can define object types by using the `@strawberry.type`
decorator, like this:

<CodeGrid>

```python
import strawberry


@strawberry.type
class Character:
    name: str
    age: int
```

```graphql
type Character {
  name: String!
  age: int!
}
```

</CodeGrid>

You can also refer to other types, like this:

<CodeGrid>

```python
import strawberry


@strawberry.type
class Character:
    name: str
    age: int


@strawberry.type
class Book:
    title: str
    main_character: Character
```

```graphql
type Character {
  name: String!
  age: Int!
}

type Book {
  title: String!
  mainCharacter: Character!
}
```

</CodeGrid>

Object types can subclass other object types to reuse their fields, as long as
the subclass is decorated too:

<CodeGrid>

```python
import strawberry


@strawberry.type
class Character:
    name: str
    age: int


@strawberry.type
class Wizard(Character):
    house: str
```

```graphql
type Character {
  name: String!
  age: Int!
}

type Wizard {
  name: String!
  age: Int!
  house: String!
}
```

</CodeGrid>

An undecorated subclass would be published as its parent type, without its own
fields, so Strawberry raises an error when one is used in the schema. The same
applies to input types and interfaces.

## Customizing fields with `Annotated`

You can configure fields by adding `strawberry.field()` to
[`typing.Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated).
This syntax works on object types, input types, and interfaces, including when
using `from __future__ import annotations`:

```python
from typing import Annotated

import strawberry


@strawberry.type
class User:
    name: Annotated[
        str,
        strawberry.field(name="displayName", description="The displayed name"),
    ]
    tags: Annotated[list[str], strawberry.field(default_factory=list)]
```

All `strawberry.field()` options are supported. In particular, `default` and
`default_factory` also configure the generated dataclass constructor, so
`User(name="Patrick")` in the example above gets a new empty `tags` list.

On Python 3.11 through 3.13, Strawberry can only read the `strawberry.field()`
options when it can evaluate the annotation when the type is created. When the
field type is defined further down the module, or only imported under
`TYPE_CHECKING`, pass the options as the field's default
(`account: Account = strawberry.field(...)`), define the type first, or use
`strawberry.lazy()` for it, which works together with field metadata:

```python
from typing import TYPE_CHECKING, Annotated

import strawberry

if TYPE_CHECKING:
    from .users import User


@strawberry.type
class Post:
    author: Annotated[
        "User",
        strawberry.lazy(".users"),
        strawberry.field(description="The post author"),
    ]
```

Otherwise Strawberry raises an
[`UnresolvedStrawberryFieldError`](https://errors.strawberry.rocks/unresolved-strawberry-field)
when the type is created, instead of ignoring options like permissions. Python
3.14 and newer read the options on a direct unresolved reference without
`strawberry.lazy()`.

The field configuration can be combined with other Strawberry metadata. The
order of the metadata does not matter:

```python
@strawberry.type
class Query:
    result: Annotated[
        Success | Failure,
        strawberry.union("Result"),
        strawberry.field(description="The operation result"),
    ]
```

Use only one `strawberry.field()` for each field. You can alternatively use the
equivalent assignment syntax, such as
`name: str = strawberry.field(description="The displayed name")`.

`strawberry.field()` must be metadata on the field's outermost `Annotated` type.
Placing it inside a wrapper configures no GraphQL field, so Strawberry raises an
error instead of silently ignoring it:

```python
# Incorrect: strawberry.field() describes the list item, not `names`.
names: list[Annotated[str, strawberry.field(description="A name")]]

# Correct: strawberry.field() describes `names`.
names: Annotated[list[str], strawberry.field(description="The names")]
```

## API

`@strawberry.type(name: str = None, description: str = None)`

Creates an object type from a class definition.

`name`: if set this will be the GraphQL name, otherwise the GraphQL will be
generated by camel-casing the name of the class.

`description`: this is the GraphQL description that will be returned when
introspecting the schema or when navigating the schema using GraphiQL.

---

### Types Operation Directives (`docs/types/operation-directives.md`)

---
title: Operation directives
---

# Operation directives

GraphQL uses directives to modify the evaluation of an item in the schema or the
operation. Operation directives can be included inside any operation (query,
subscription, mutation) and can be used to modify the execution of the operation
or the values returned by the operation.

Directives can help avoid having to create resolvers for values that can be
computed via the values of additional fields.

All Directives are proceeded by `@` symbol

# Default Operation directives

Strawberry provides the following default operation directives:

- `@skip(if: Boolean!)` - if Boolean is true, the given item is NOT resolved by
  the GraphQL Server

- `@include(if: Boolean!)` - if Boolean is false, the given item is NOT resolved
  by the GraphQL Server

## Experimental Directives

When
[experimental incremental execution](./schema-configurations#enable_experimental_incremental_execution)
is enabled, these additional directives become available:

- `@defer(if: Boolean, label: String)` - Allows fields to be resolved
  asynchronously and delivered incrementally. The field will be omitted from the
  initial response and sent in a subsequent payload.

- `@stream(if: Boolean, label: String, initialCount: Int)` - Enables streaming
  of list fields. The list will be delivered incrementally, with `initialCount`
  items in the initial response and remaining items in subsequent payloads.

<Note>

These experimental directives must be enabled via schema configuration. See
[Defer and Stream](./defer-and-stream) for detailed usage information.

</Note>

<Note>

`@deprecated(reason: String)` IS NOT compatible with Operation directives.
`@deprecated` is exclusive to [Schema Directives](./schema-directives.md)

</Note>

**Examples of Default Operation directives**

```graphql
# @include
query getPerson($includePoints: Boolean!) {
  person {
    name
    points @include(if: $includePoints)
  }
}

# @skip
query getPerson($hideName: Boolean!) {
  person {
    name @skip(if: $hideName)
    points
  }
}
```

# Custom Operation directives

Custom directives must be defined in the schema to be used within the query and
can be used to decorate other parts of the schema.

```python
# Definition
@strawberry.directive(
    locations=[DirectiveLocation.FIELD], description="Make string uppercase"
)
def turn_uppercase(value: DirectiveValue[str]):
    return value.upper()


@strawberry.directive(locations=[DirectiveLocation.FIELD])
def replace(value: DirectiveValue[str], old: str, new: str):
    return value.replace(old, new)
```

```graphql
# Use
query People($identified: Boolean!) {
  person {
    name @turnUppercase
  }
  duck: person {
    name @replace(old: "Duck", new: "Duck")
  }
  johnDoe: person {
    name @replace(old: "Duck", new: "John") @include(if: $identified)
  }
}
```

# Locations for Operation directives

Directives can only appear in _specific_ locations inside the query. These
locations must be included in the directive's definition. In Strawberry the
location is defined in the directive function's parameter `locations`.

```graphql
@strawberry.directive(locations=[DirectiveLocation.FIELD])
```

**Operation directives possible locations**

Operation directives can be applied to many different parts of an operation.
Here's the list of all the allowed locations:

- `QUERY`
- `MUTATION`
- `SUBSCRIPTION`
- `FIELD`
- `FRAGMENT_DEFINITION`
- `FRAGMENT_SPREAD`
- `INLINE_FRAGMENT`

---

### Types Private (`docs/types/private.md`)

---
title: Private Fields
---

# Private Fields

Private (external) fields can provide local context for later resolution. These
fields will act as plain fields so will not be exposed in the GraphQL API.

Some uses include:

- Context that relies upon field inputs.
- Avoiding fully materializing an object hierarchy (lazy resolution)

# Defining a private field

Specifying a field with `strawberry.Private[...]` will desigate it as internal
and not for GraphQL.

# Example

Consider the following type, which can accept any Python object and handle
converting it to string, representation, or templated output:

```python
@strawberry.type
class Stringable:
    value: strawberry.Private[object]

    @strawberry.field
    def string(self) -> str:
        return str(self.value)

    @strawberry.field
    def repr(self) -> str:
        return repr(self.value)

    @strawberry.field
    def format(self, template: str) -> str:
        return template.format(my=self.value)
```

The `Private[...]` type lets Strawberry know that this field is not a GraphQL
field. "value" is a regular field on the class, but it is not exposed on the
GraphQL API.

```python
@strawberry.type
class Query:
    @strawberry.field
    def now(self) -> Stringable:
        return Stringable(value=datetime.datetime.now())
```

Queries can then select the fields and formats desired, but formatting only
happens as requested:

<CodeGrid>

```graphql
{
  now {
    format(template: "{my.year}")
    string
    repr
  }
}
```

```json
{
  "data": {
    "now": {
      "format": "2022",
      "string": "2022-09-03 17:03:04.923068",
      "repr": "datetime.datetime(2022, 9, 3, 17, 3, 4, 923068)"
    }
  }
}
```

</CodeGrid>

---

### Types Resolvers (`docs/types/resolvers.md`)

---
title: Resolvers
---

# Resolvers

When defining a GraphQL schema, you usually start with the definition of the
schema for your API, for example, let's take a look at this schema:

<CodeGrid>

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type
class Query:
    last_user: User
```

```graphql
type User {
  name: String!
}

type Query {
  lastUser: User!
}
```

</CodeGrid>

We have defined a `User` type and a `Query` type. Next, to define how the data
is returned from our server, we will attach resolvers to our fields.

## Let's define a resolver

Let's create a resolver and attach it to the `lastUser` field. A resolver is a
Python function that returns data. In Strawberry there are two ways of defining
resolvers; the first is to pass a function to the field definition, like this:

```python
import strawberry


@strawberry.type
class User:
    name: str


def get_last_user() -> User:
    return User(name="Marco")


@strawberry.type
class Query:
    last_user: User = strawberry.field(resolver=get_last_user)
```

Now when Strawberry executes the following query, it will call the
`get_last_user` function to fetch the data for the `lastUser` field:

<CodeGrid>

```graphql
{
  lastUser {
    name
  }
}
```

```json
{
  "data": {
    "lastUser": {
      "name": "Marco"
    }
  }
}
```

</CodeGrid>

## Defining resolvers as methods

The other way to define a resolver is to use `strawberry.field` as a decorator,
like here:

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type
class Query:
    @strawberry.field
    def last_user(self) -> User:
        return User(name="Marco")
```

This is useful when you want to co-locate resolvers and types or when you have
very small resolvers.

<Note>

If you're curious how the `self` parameter works in the resolver, you can read
more about it in the
[accessing parent data guide](../guides/accessing-parent-data.md).

</Note>

## Defining arguments

Fields can also have arguments; in Strawberry the arguments for a field are
defined on the resolver, as you would normally do in a Python function. Let's
define a field on a Query that returns a user by ID:

<CodeGrid>

```python
import strawberry


@strawberry.type
class User:
    name: str


@strawberry.type
class Query:
    @strawberry.field
    def user(self, id: strawberry.ID) -> User:
        # here you'd use the `id` to get the user from the database
        return User(name="Marco")
```

```graphql
type User {
  name: String!
}

type Query {
  user(id: ID!): User!
}
```

</CodeGrid>

### Optional arguments

Optional or nullable arguments can be expressed using `Optional`:

```python
from typing import Optional
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def hello(self, name: Optional[str] = None) -> str:
        if name is None:
            return "Hello world!"
        return f"Hello {name}!"
```

If you need to differentiate between `null` and no arguments being passed (for
example, distinguishing between "set to null" vs "don't change"), you can use
`strawberry.Maybe`. See the [Maybe documentation](./maybe.md) for comprehensive
usage examples and patterns.

### Annotated Arguments

Additional metadata can be added to arguments, for example a custom name or
deprecation reason, using `strawberry.argument` with
[typing.Annotated](https://docs.python.org/3/library/typing.html#typing.Annotated):

```python
from typing import Optional, Annotated
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def greet(
        self,
        name: Optional[str] = None,
        is_morning: Annotated[
            Optional[bool],
            strawberry.argument(
                name="morning",
                deprecation_reason="The field now automatically detects if it's morning or not",
            ),
        ] = None,
    ) -> str: ...
```

## Accessing execution information

Sometimes it is useful to access the information for the current execution
context. Strawberry allows to declare a parameter of type `Info` that will be
automatically passed to the resolver. This parameter contains the information
for the current execution context.

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


def full_name(root: "User", info: strawberry.Info) -> str:
    return f"{root.first_name} {root.last_name} {info.field_name}"


@strawberry.type
class User:
    first_name: str
    last_name: str
    full_name: str = strawberry.field(resolver=full_name)
```

<Tip>

You don't have to call this parameter `info`, its name can be anything.
Strawberry uses the type to pass the correct value to the resolver.

</Tip>

### API

Info objects contain information for the current execution context:

`class Info(Generic[ContextType, RootValueType])`

| Parameter name  | Type                      | Description                                                           |
| --------------- | ------------------------- | --------------------------------------------------------------------- |
| field_name      | `str`                     | The name of the current field (generally camel-cased)                 |
| python_name     | `str`                     | The 'Python name' of the field (generally snake-cased)                |
| context         | `ContextType`             | The value of the context                                              |
| root_value      | `RootValueType`           | The value for the root type                                           |
| variable_values | `Dict[str, Any]`          | The variables for this operation                                      |
| query           | `str \| None`             | The full GraphQL document string sent in the request                  |
| operation       | `OperationDefinitionNode` | The ast for the current operation (public API might change in future) |
| path            | `Path`                    | The path for the current field                                        |
| selected_fields | `List[SelectedField]`     | Additional information related to the current field                   |
| schema          | `Schema`                  | The Strawberry schema instance                                        |

---

### Types Scalars (`docs/types/scalars.md`)

---
title: Scalars
---

# Scalars

Scalar types represent concrete values at the leaves of a query. For example in
the following query the `name` field will resolve to a scalar type (in this case
it's a `String` type):

<CodeGrid>

```graphql "name"
{
  user {
    name
  }
}
```

```json '"name": "Patrick"'
{
  "data": {
    "user": {
      "name": "Patrick"
    }
  }
}
```

</CodeGrid>

There are several built-in scalars, and you can define custom scalars too.
([Enums](/docs/types/enums) are also leaf values.) The built in scalars are:

- `String`, maps to Python’s `str`
- `Int`, a signed 32-bit integer, maps to Python’s `int`
- `Float`, a signed double-precision floating-point value, maps to Python’s
  `float`
- `Boolean`, true or false, maps to Python’s `bool`
- `ID`, a specialised `String` for representing unique object identifiers
- `Date`, an ISO-8601 encoded
  [date](https://docs.python.org/3/library/datetime.html#date-objects)
- `DateTime`, an ISO-8601 encoded
  [datetime](https://docs.python.org/3/library/datetime.html#datetime-objects)
- `Time`, an ISO-8601 encoded
  [time](https://docs.python.org/3/library/datetime.html#time-objects)
- `Decimal`, a
  [Decimal](https://docs.python.org/3/library/decimal.html#decimal.Decimal)
  value serialized as a string
- `UUID`, a [UUID](https://docs.python.org/3/library/uuid.html#uuid.UUID) value
  serialized as a string
- `Void`, always null, maps to Python’s `None`
- `JSON`, a JSON value as specified in
  [ECMA-404](https://ecma-international.org/publications-and-standards/standards/ecma-404/)
  standard, maps to Python’s `dict`
- `Base16`, `Base32`, `Base64`, represents hexadecimal strings encoded with
  `Base16`/`Base32`/`Base64`. As specified in
  [RFC4648](https://datatracker.ietf.org/doc/html/rfc4648.html). Maps to
  Python’s `str`

Fields can return built-in scalars by using the Python equivalent:

<CodeGrid>

```python
import datetime
import decimal
import uuid
import strawberry


@strawberry.type
class Product:
    id: uuid.UUID
    name: str
    stock: int
    is_available: bool
    available_from: datetime.date
    same_day_shipping_before: datetime.time
    created_at: datetime.datetime
    price: decimal.Decimal
    void: None
```

```graphql
type Product {
  id: UUID!
  name: String!
  stock: Int!
  isAvailable: Boolean!
  availableFrom: Date!
  sameDayShippingBefore: Time!
  createdAt: DateTime!
  price: Decimal!
  void: Void
}
```

</CodeGrid>

Scalar types can also be used as inputs:

```python 'date_input: datetime.date'
import datetime
import strawberry


@strawberry.type
class Query:
    @strawberry.field
    def one_week_from(self, date_input: datetime.date) -> datetime.date:
        return date_input + datetime.timedelta(weeks=1)
```

## Custom scalars

You can create custom scalars for your schema to represent specific types in
your data model. This can be helpful to let clients know what kind of data they
can expect for a particular field.

To define a custom scalar you need to give it a name and functions that tell
Strawberry how to serialize and deserialise the type.

For example here is a custom scalar type to represent a Base64 string:

```python
import base64
from typing import NewType

import strawberry
from strawberry.schema.config import StrawberryConfig

Base64 = NewType("Base64", bytes)


@strawberry.type
class Query:
    @strawberry.field
    def base64(self) -> Base64:
        return Base64(b"hi")


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(
        scalar_map={
            Base64: strawberry.scalar(
                name="Base64",
                serialize=lambda v: base64.b64encode(v).decode("utf-8"),
                parse_value=lambda v: base64.b64decode(v.encode("utf-8")),
            )
        }
    ),
)

result = schema.execute_sync("{ base64 }")

assert result.data == {"base64": "aGk="}
```

<Note>

The `Base16`, `Base32` and `Base64` scalar types are available in
`strawberry.scalars`

```python
from strawberry.scalars import Base16, Base32, Base64
```

</Note>

### Classifying invalid custom scalar input

Strawberry cannot determine whether an arbitrary exception from a custom
`parse_value` function represents invalid client input or a bug in the parser.
To make an expected conversion error identifiable by server-side error handling,
raise `StrawberryInputCoercionError` explicitly:

```python
import uuid
from typing import NewType

import strawberry
from strawberry.exceptions import StrawberryInputCoercionError

OrderID = NewType("OrderID", uuid.UUID)


def parse_order_id(value: object) -> OrderID:
    if not isinstance(value, str):
        raise StrawberryInputCoercionError("OrderID must be a string")

    try:
        return OrderID(uuid.UUID(value))
    except ValueError:
        raise StrawberryInputCoercionError("Invalid OrderID") from None


order_id_scalar = strawberry.scalar(
    name="OrderID",
    serialize=str,
    parse_value=parse_order_id,
)
```

The resulting scalar definition can be added to `StrawberryConfig.scalar_map`.
Only catch exceptions that represent expected conversion errors so unexpected
parser exceptions continue to be reported as server faults. See
[Dealing with errors](../guides/errors#strawberry-input-coercion-errors) for how
to identify direct and wrapped coercion errors.

## Example: Custom Object Scalar

Suppose we would like to use a Pillow `Image` as a scalar that serializes
to/from base64-encoded bytes:

```python
import base64
from io import BytesIO

from PIL import Image

import strawberry
from strawberry.schema.config import StrawberryConfig


@strawberry.type
class Query:
    @strawberry.field
    def generate_image(self) -> Image.Image:
        # Create a simple 100x100 red image
        return Image.new("RGB", (100, 100), color="red")


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(
        scalar_map={
            Image.Image: strawberry.scalar(
                name="Image",
                description="A Pillow Image, serialized as base64-encoded PNG",
                serialize=lambda img: base64.b64encode(img.tobytes("png")).decode(
                    "utf-8"
                ),
                parse_value=lambda v: Image.open(BytesIO(base64.b64decode(v))),
            )
        }
    ),
)
```

This generates the following schema:

```graphql
"""
A Pillow Image, serialized as base64-encoded PNG
"""
scalar Image

type Query {
  generateImage: Image!
}
```

<CodeGrid>

```graphql
query {
  generateImage
}
```

```json
{
  "data": {
    "generateImage": "iVBORw0KGgoAAAANSUhEUgAAAAE..."
  }
}
```

</CodeGrid>

## Example: NewType Scalar

Suppose we would like to have a type-safe `Currency` scalar based on `Decimal`:

```python
from decimal import Decimal
from typing import NewType

import strawberry
from strawberry.schema.config import StrawberryConfig

# Define a NewType for currency - this is a proper type that type checkers understand
Currency = NewType("Currency", Decimal)


@strawberry.type
class Query:
    @strawberry.field
    def price(self) -> Currency:
        return Currency("19.99")


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(
        scalar_map={
            Currency: strawberry.scalar(
                name="Currency",
                description="A monetary value with 2 decimal places",
                serialize=lambda v: str(v.quantize(Decimal("0.01"))),
                parse_value=lambda v: Currency(v).quantize(Decimal("0.01")),
            )
        }
    ),
)
```

This generates the following schema:

```graphql
"""
A monetary value with 2 decimal places
"""
scalar Currency

type Query {
  price: Currency!
}
```

<CodeGrid>

```graphql
query {
  price
}
```

```json
{
  "data": {
    "price": "19.99"
  }
}
```

</CodeGrid>

<Note>

The `JSON` scalar type is available in `strawberry.scalars`:

```python
from strawberry.scalars import JSON
```

</Note>

## Overriding built-in scalars

To override the behaviour of the built-in scalars, you can pass a `scalar_map`
in your schema config.

Here is a full example of replacing the built-in `DateTime` scalar with one that
serializes all datetimes as Unix timestamps:

```python
from datetime import datetime, timezone
import strawberry
from strawberry.schema.config import StrawberryConfig


@strawberry.type
class Query:
    @strawberry.field
    def current_time(self) -> datetime:
        return datetime.now()


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(
        scalar_map={
            datetime: strawberry.scalar(
                name="DateTime",
                serialize=lambda value: int(value.timestamp()),
                parse_value=lambda value: datetime.fromtimestamp(
                    int(value), timezone.utc
                ),
            ),
        }
    ),
)
result = schema.execute_sync("{ currentTime }")
assert result.data == {"currentTime": 1628683200}
```

### Replacing datetime with the popular `pendulum` library

To override with a pendulum instance you'd want to serialize and parse_value
like the above example. Let's throw them in a class this time.

In addition we'll be using the `Union` clause to combine possible input types.
Since pendulum isn't typed yet, we'll have to silence mypy's errors using
`# type: ignore`

```python
import pendulum
from datetime import datetime
from typing import Union

import strawberry
from strawberry.schema.config import StrawberryConfig


def serialize_datetime(dt: Union[pendulum.DateTime, datetime]) -> str:  # type: ignore
    try:
        return dt.isoformat()
    except ValueError:
        return dt.to_iso8601_string()  # type: ignore


def parse_datetime(value: str) -> Union[pendulum.DateTime, datetime]:  # type: ignore
    return pendulum.parse(value)  # type: ignore


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(
        scalar_map={
            datetime: strawberry.scalar(
                name="DateTime",
                description="A date and time",
                serialize=serialize_datetime,
                parse_value=parse_datetime,
            ),
        }
    ),
)
```

## BigInt (64-bit integers)

Python integers have arbitrary precision (no size limit). However, the GraphQL
spec limits integers to 32-bit signed values (approximately ±2 billion).

This will inevitably raise errors. Instead of using strings on the client as a
workaround, you could use the following approach:

```python
from typing import NewType, Union

import strawberry
from strawberry.schema.config import StrawberryConfig

BigInt = NewType("BigInt", int)


@strawberry.type
class Query:
    @strawberry.field
    def large_number(self) -> BigInt:
        return BigInt(9007199254740993)


schema = strawberry.Schema(
    Query,
    config=StrawberryConfig(
        scalar_map={
            BigInt: strawberry.scalar(
                name="BigInt",
                description="BigInt field",
                serialize=lambda v: int(v),
                parse_value=lambda v: str(v),
            ),
        }
    ),
)
```

You can adapt your schema to automatically use this scalar for all integers by
adding `int` to the `scalar_map`:

<Tip>
  Only use this override if you expect most of your integers to be 64-bit. Since
  most GraphQL schemas follow standardized design patterns and most clients
  require additional effort to handle all numbers as strings, it makes more
  sense to reserve BigInt for numbers that actually exceed the 32-bit limit. You
  can achieve this by annotating `BigInt` instead of `int` in your resolvers
  handling large python integers.
</Tip>

```python
schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    subscription=Subscription,
    config=StrawberryConfig(
        scalar_map={
            int: strawberry.scalar(
                name="BigInt",
                serialize=lambda v: int(v),
                parse_value=lambda v: str(v),
            ),
        }
    ),
)
```

---

--- METRICS ---
- Files Extracted: 138
- Estimated Token Budget: ~126612 tokens
- Canonical Reference: https://codewiki.google/github.com/strawberry-graphql/strawberry
