Skip to content

Commit e104af8

Browse files
authored
Fix operation directive argument coercion (#4596)
1 parent 153b88b commit e104af8

8 files changed

Lines changed: 245 additions & 42 deletions

File tree

RELEASE.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
release type: patch
3+
social_messages:
4+
x: >-
5+
{project_name} {version} is out! Operation directive resolvers now receive
6+
correctly typed arguments, including inputs, enums, custom scalars, and
7+
defaults. 🍓 https://strawberry.rocks/release/{version}
8+
linkedin: >-
9+
{project_name} {version} is out. Operation directive arguments now behave
10+
like field arguments, with standard GraphQL coercion and Strawberry input
11+
conversion for literals, variables, defaults, and explicit null values. 🍓
12+
---
13+
14+
This release fixes argument handling for operation directive resolvers.
15+
16+
Arguments passed to operation directives now use GraphQL's standard coercion before
17+
your resolver runs. Directive resolvers receive Python numeric values, Strawberry
18+
enum members and nested input objects, and values parsed by custom scalars, whether
19+
clients use literals or variables.
20+
21+
When a client omits a variable, Strawberry now applies the directive argument's
22+
default. Explicit `null` continues to reach nullable arguments as `None`.

docs/types/operation-directives.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ query People($identified: Boolean!) {
9898
person {
9999
name @turnUppercase
100100
}
101-
jess: person {
102-
name @replace(old: "Jess", new: "Jessica")
101+
duck: person {
102+
name @replace(old: "Duck", new: "Duck")
103103
}
104104
johnDoe: person {
105-
name @replace(old: "Jess", new: "John") @include(if: $identified)
105+
name @replace(old: "Duck", new: "John") @include(if: $identified)
106106
}
107107
}
108108
```

strawberry/extensions/directives.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
from typing import TYPE_CHECKING, Any
44

5+
from graphql import get_argument_values
6+
57
from strawberry.extensions import SchemaExtension
6-
from strawberry.types.nodes import convert_arguments
8+
from strawberry.types.arguments import convert_arguments
9+
from strawberry.utils import IS_GQL_33
710
from strawberry.utils.await_maybe import await_maybe
811

912
if TYPE_CHECKING:
@@ -76,7 +79,25 @@ def process_directive(
7679
strawberry_directive = schema.get_directive_by_name(directive_name)
7780
assert strawberry_directive is not None, f"Directive {directive_name} not found"
7881

79-
arguments = convert_arguments(info=info, nodes=directive.arguments)
82+
directive_definition = info.schema.get_directive(directive_name)
83+
assert directive_definition is not None, f"Directive {directive_name} not found"
84+
85+
variable_values: Any = info.variable_values
86+
if IS_GQL_33 and not hasattr(variable_values, "coerced"):
87+
# Strawberry exposes a plain dict, while graphql-core 3.3 expects its
88+
# VariableValues container when coercing arguments.
89+
from graphql.execution import values as execution_values
90+
91+
variable_values_type = vars(execution_values)["VariableValues"]
92+
variable_values = variable_values_type({}, variable_values)
93+
94+
arguments = get_argument_values(directive_definition, directive, variable_values)
95+
arguments = convert_arguments(
96+
arguments,
97+
strawberry_directive.arguments,
98+
scalar_registry=schema.schema_converter.scalar_registry,
99+
config=schema.config,
100+
)
80101
resolver = strawberry_directive.resolver
81102

82103
info_parameter = resolver.info_parameter

tests/schema/extensions/schema_extensions/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def assert_expected(cls) -> None:
4747
def default_query_types_and_query() -> SchemaHelper:
4848
@strawberry.type
4949
class Person:
50-
name: str = "Jess"
50+
name: str = "Duck"
5151

5252
@strawberry.type
5353
class Query:

tests/schema/extensions/schema_extensions/test_extensions.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
def test_base_extension():
1919
@strawberry.type
2020
class Person:
21-
name: str = "Jess"
21+
name: str = "Duck"
2222

2323
@strawberry.type
2424
class Query:
@@ -62,7 +62,7 @@ class ExtensionNoHooks(SchemaExtension): ...
6262

6363
@strawberry.type
6464
class Person:
65-
name: str = "Jess"
65+
name: str = "Duck"
6666

6767
@strawberry.type
6868
class Query:
@@ -100,7 +100,7 @@ def on_parse(self):
100100

101101
@strawberry.type
102102
class Person:
103-
name: str = "Jess"
103+
name: str = "Duck"
104104

105105
@strawberry.type
106106
class Query:
@@ -135,7 +135,7 @@ def on_operation(self):
135135

136136
@strawberry.type
137137
class Person:
138-
name: str = "Jess"
138+
name: str = "Duck"
139139

140140
@strawberry.type
141141
class Query:
@@ -288,7 +288,7 @@ async def on_parse(self):
288288

289289
@strawberry.type
290290
class Person:
291-
name: str = "Jess"
291+
name: str = "Duck"
292292

293293
@strawberry.type
294294
class Query:

tests/schema/extensions/test_apollo.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_tracing_sync(mocker):
2121

2222
@strawberry.type
2323
class Person:
24-
name: str = "Jess"
24+
name: str = "Duck"
2525

2626
@strawberry.type
2727
class Query:
@@ -76,7 +76,7 @@ async def test_tracing_async(mocker):
7676

7777
@strawberry.type
7878
class Person:
79-
name: str = "Jess"
79+
name: str = "Duck"
8080

8181
@strawberry.type
8282
class Query:
@@ -143,7 +143,7 @@ def test_should_not_trace_introspection_sync_queries(mocker):
143143

144144
@strawberry.type
145145
class Person:
146-
name: str = "Jess"
146+
name: str = "Duck"
147147

148148
@strawberry.type
149149
class Query:
@@ -178,7 +178,7 @@ async def test_should_not_trace_introspection_async_queries(mocker):
178178

179179
@strawberry.type
180180
class Person:
181-
name: str = "Jess"
181+
name: str = "Duck"
182182

183183
@strawberry.type
184184
class Query:

tests/schema/extensions/test_opentelemetry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def global_tracer_mock(mocker: MockerFixture) -> MagicMock:
1919

2020
@strawberry.type
2121
class Person:
22-
name: str = "Jess"
22+
name: str = "Duck"
2323

2424

2525
@strawberry.type

0 commit comments

Comments
 (0)