File: query-codegen.md

package info (click to toggle)
strawberry-graphql 0.306.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 18,176 kB
  • sloc: javascript: 178,052; python: 65,643; sh: 33; makefile: 25
file content (177 lines) | stat: -rw-r--r-- 4,437 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
---
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."""
        ...
```