Closed ichorid closed 3 weeks ago
Would love to know if this is fixable. We just ran into this issue as well. We have a Java client that fails introspection of our Strawberry APIs because some default int values are strings instead of ints.
@krispharper can you show us the error?
I've made a reproduction for this: https://play.strawberry.rocks/?gist=482103631096241ca1a08f95aeed655a
But to clarify, this behaviour is from GraphQL core and we don't have a lot of control over it 😊
Also I think the spec allows this: https://spec.graphql.org/October2021/#sec-The-__InputValue-Type (but I might have read it wrong :) )
@krispharper can you share the client implementation you're using?
I'm with Patrick on this one. The type of __InputValue.defaultValue
is string:
type __InputValue {
name: String!
description: String
type: __Type!
defaultValue: String
}
Source: Schema introspection schema, GraphQL Spec: https://spec.graphql.org/October2021/#sec-Schema-Introspection.Schema-Introspection-Schema
This is a bug that needs to be raised with the individual libraries not following the spec.
It very well might be an issue with the client library. I'll try to make a reproducible example this weekend.
I just ran into this as well, any possible solutions? I'm trying to connect my graphql api to hasura
To solve this, I implemented a custom starlette middleware to intercept and modify the graphQL introspection response:
The middleware "IntrospectionMiddleware" checks for graphQL introspection queries by inspecting the response and, if found, evaluates and corrects the defaultValue fields in the introspection data. This avoids issues like "true" being treated as a string instead of a boolean.
Hope it helps:
def evaluate_default_values(data):
if isinstance(data, dict):
new_dict = {}
for key, value in data.items():
if key == "defaultValue":
pass
# HERE: Evaluate the null cases
# try:
# if not value or value == "null":
# pass
# elif value == "true":
# new_dict[key] = True
# else:
# print(f"Value: {value}")
# new_dict[key] = value # eval(value)
# except (SyntaxError, NameError) as e:
# print(f"Error evaluating defaultValue: {e}")
# new_dict[key] = value # Keep original value if evaluation fails
else:
new_dict[key] = evaluate_default_values(value)
return new_dict
elif isinstance(data, list):
new_list = []
for item in data:
new_list.append(evaluate_default_values(item))
return new_list
else:
return copy.deepcopy(data)
async def modify_response(body_iterator):
chunks = []
async for chunk in body_iterator:
chunks.append(chunk)
# Combine all chunks and decode to a single string
full_body = b"".join(chunks).decode("utf-8")
data = json.loads(full_body)
if "data" in data and data["data"] and "__schema" in data["data"]:
data["data"]["__schema"] = evaluate_default_values(data["data"]["__schema"])
modified_body = json.dumps(data)
yield modified_body.encode("utf-8")
class IntrospectionMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
response = await call_next(request)
# Check if it's the introspection query
if (
response.headers.get("content-type") == "application/json"
and request.url.path == "/graphql"
and response.status_code == 200
):
if isinstance(response, StreamingResponse):
original_body_iterator = response.body_iterator
response.body_iterator = modify_response(original_body_iterator)
return response
@x0y-gt great to hear you found a workaround for your case. Also, thanks for sharing it. This will surely help others facing the same problem with hasura 😊
This avoids issues like "true" being treated as a string instead of a boolean.
I just want to reiterate that this is not an issue and actually the way it is intended by the spec. See https://spec.graphql.org/October2021/#sec-Schema-Introspection.Schema-Introspection-Schema for the GraphQL schema for introspection. The Type __InputValue has a field defaultValue
of type String
.
Values of any type other than string (such as true) are actually not spec-compliant. Closing this, since this is a bug in the consumer libraries rather than strawberry or GraphQL-Core.
When declaring an optional argument with a scalar type, its default value is passed as a string in the resulting schema. This makes Strawberry-declared schemas incompatible with externally connected GraphQL consumers with strict schema checkers, such as Hasura.
The following code:
produces the following default values in the schema:
Schema inspection
```graphql { "data": { "__schema": { "queryType": { "name": "Query" }, "mutationType": null, "types": [ { "kind": "OBJECT", "name": "Query", "description": null, "fields": [ { "name": "example", "description": null, "args": [ { "name": "baz", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null }, { "name": "foo", "description": null, "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "null" }, { "name": "bar", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": "10" } ```System Information
Python 3.11 Ubuntu 22.10 Strawberry version: 0.209.2
Upvote & Fund