Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to disable field suggestions #3537

Merged
merged 4 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Release type: minor

This release adds a new configuration to disable field suggestions in the error
response.

```python
@strawberry.type
class Query:
name: str


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

Trying to query `{ nam }` will not suggest to query `name` instead.
6 changes: 6 additions & 0 deletions TWEET.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
🆕 Release $version is out! Thanks to $contributor for the PR 👏

This release allows to disable field suggestions when sending an operation with
the wrong field.

Get it here 👉 $release_url
76 changes: 74 additions & 2 deletions docs/types/schema-configurations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ title: Schema Configurations
# Schema Configurations

Strawberry allows to customise how the schema is generated by passing
configurations. At the moment we only allow to disable auto camel casing of
fields and arguments names.
patrick91 marked this conversation as resolved.
Show resolved Hide resolved
configurations.

To customise the schema you can create an instance of `StrawberryConfig`, as
shown in the example below:
Expand All @@ -33,3 +32,76 @@ type Query {
example_field: String!
}
```

## Available configurations

Here's a list of the available configurations:

### auto_camel_case

By default Strawberry will convert the field names to camel case, so a field
like `example_field` will be converted to `exampleField`. You can disable this
feature by setting `auto_camel_case` to `False`.

```python
schema = strawberry.Schema(query=Query, config=StrawberryConfig(auto_camel_case=False))
```

### default_resolver

By default Strawberry will use the `getattr` function as the default resolver.
You can customise this by setting the `default_resolver` configuration.

This can be useful in cases you want to allow returning a dictionary from a
resolver.

```python
import strawberry

from strawberry.schema.config import StrawberryConfig


def custom_resolver(obj, field):
try:
return obj[field]
except (KeyError, TypeError):
return getattr(obj, field)


@strawberry.type
class User:
name: str


@strawberry.type
class Query:
@strawberry.field
def user(self, info) -> User: # this won't type check, but will work at runtime
return {"name": "Patrick"}


schema = strawberry.Schema(
query=Query, config=StrawberryConfig(default_resolver=custom_resolver)
)
```

### relay_max_results

By default Strawberry's max limit for relay connections is 100. You can
customise this by setting the `relay_max_results` configuration.

```python
schema = strawberry.Schema(query=Query, config=StrawberryConfig(relay_max_results=50))
```

### disable_field_suggestions

By default Strawberry will suggest fields when a field is not found in the
schema. You can disable this feature by setting `disable_field_suggestions` to
`True`.

```python
schema = strawberry.Schema(
query=Query, config=StrawberryConfig(disable_field_suggestions=True)
)
```
19 changes: 19 additions & 0 deletions strawberry/schema/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,25 @@ def get_directive_by_name(self, graphql_name: str) -> Optional[StrawberryDirecti
def as_str(self) -> str:
raise NotImplementedError

@staticmethod
def remove_field_suggestion(error: GraphQLError) -> None:
patrick91 marked this conversation as resolved.
Show resolved Hide resolved
if (
error.message.startswith("Cannot query field")
and "Did you mean" in error.message
):
error.message = error.message.split("Did you mean")[0].strip()

def _process_errors(
self,
errors: List[GraphQLError],
execution_context: Optional[ExecutionContext] = None,
) -> None:
if self.config.disable_field_suggestions:
for error in errors:
self.remove_field_suggestion(error)

self.process_errors(errors, execution_context)
patrick91 marked this conversation as resolved.
Show resolved Hide resolved

def process_errors(
self,
errors: List[GraphQLError],
Expand Down
1 change: 1 addition & 0 deletions strawberry/schema/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class StrawberryConfig:
name_converter: NameConverter = field(default_factory=NameConverter)
default_resolver: Callable[[Any, str], object] = getattr
relay_max_results: int = 100
disable_field_suggestions: bool = False

def __post_init__(
self,
Expand Down
4 changes: 2 additions & 2 deletions strawberry/schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ async def execute(
execution_context_class=self.execution_context_class,
execution_context=execution_context,
allowed_operation_types=allowed_operation_types,
process_errors=self.process_errors,
process_errors=self._process_errors,
)

return result
Expand Down Expand Up @@ -301,7 +301,7 @@ def execute_sync(
execution_context_class=self.execution_context_class,
execution_context=execution_context,
allowed_operation_types=allowed_operation_types,
process_errors=self.process_errors,
process_errors=self._process_errors,
)

return result
Expand Down
68 changes: 68 additions & 0 deletions tests/schema/test_execution_errors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

import strawberry
from strawberry.schema.config import StrawberryConfig


def test_runs_parsing():
Expand Down Expand Up @@ -64,3 +65,70 @@ class Query:

assert len(result.errors) == 1
assert result.errors[0].message == "Syntax Error: Expected Name, found <EOF>."


def test_suggests_fields_by_default():
patrick91 marked this conversation as resolved.
Show resolved Hide resolved
@strawberry.type
class Query:
name: str

schema = strawberry.Schema(query=Query)

query = """
query {
ample
}
"""

result = schema.execute_sync(query)

assert len(result.errors) == 1
assert (
result.errors[0].message
== "Cannot query field 'ample' on type 'Query'. Did you mean 'name'?"
)


def test_can_disable_field_suggestions():
patrick91 marked this conversation as resolved.
Show resolved Hide resolved
@strawberry.type
class Query:
name: str

schema = strawberry.Schema(
query=Query, config=StrawberryConfig(disable_field_suggestions=True)
)

query = """
query {
ample
}
"""

result = schema.execute_sync(query)

assert len(result.errors) == 1
assert result.errors[0].message == "Cannot query field 'ample' on type 'Query'."


def test_can_disable_field_suggestions_multiple_fields():
@strawberry.type
class Query:
name: str
age: str

schema = strawberry.Schema(
query=Query, config=StrawberryConfig(disable_field_suggestions=True)
)

query = """
query {
ample
ag
}
"""

result = schema.execute_sync(query)

assert len(result.errors) == 2
assert result.errors[0].message == "Cannot query field 'ample' on type 'Query'."
assert result.errors[1].message == "Cannot query field 'ag' on type 'Query'."
Loading