You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using custom scalar types, it's crucial to provide error feedback to users when issues arise with their submitted data. However, triggering exceptions within the ParseValue and ParseLiteral methods can lead to program crashes when using the graphql.Do method. This prevents the necessary error messages from being delivered to users.
#679
Open
vyks520 opened this issue
Sep 12, 2023
· 0 comments
When using custom scalar types, it's crucial to provide error feedback to users when issues arise with their submitted data. However, triggering exceptions within the ParseValue and ParseLiteral methods can lead to program crashes when using the graphql.Do method. This prevents the necessary error messages from being delivered to users.
The proposed improvement is to handle exceptions by checking the error object's type when they occur. If the error is created using gqlerrors.Error{}, it signifies that the error object's Message field contains information intended for user feedback, allowing us to capture and return that Message to users. In cases where the error is not created using gqlerrors.Error{}, it can be rethrown as an exception. This approach enhances error handling and ensures that valuable information is communicated to users while avoiding the potential exposure of sensitive information by preventing all exceptions from being exposed to the frontend.
package main
import (
"encoding/json""fmt""github.com/graphql-go/graphql""github.com/graphql-go/graphql/gqlerrors""github.com/graphql-go/graphql/language/ast""github.com/graphql-go/graphql/language/kinds""log""strconv"
)
funcPtrSliceToSlice[Tany](s []*T) []T {
ifs==nil {
returnnil
}
ret:=make([]T, 0, len(s))
for_, v:=ranges {
ret=append(ret, *v)
}
returnret
}
funcparseObject(valueASTinterface{}) interface{} {
varvalue=make(map[string]interface{})
varfieldList []ast.ObjectFieldswitchobj:=valueAST.(type) {
case []*ast.ObjectField:
fieldList=PtrSliceToSlice(obj)
case []ast.ObjectField:
fieldList=objdefault:
err:=gqlerrors.NewError(
fmt.Sprintf("JSON cannot represent value: %v", valueAST),
nil, "", nil, nil, nil)
panic(err)
}
for_, field:=rangefieldList {
value[field.Name.Value] =parseLiteral(field.Value)
}
returnvalue
}
funcparseList(valueASTinterface{}) interface{} {
varvalueList []ast.Valueswitchvs:=valueAST.(type) {
case []ast.Value:
valueList=vscase []*ast.Value:
valueList=PtrSliceToSlice(vs)
default:
err:=gqlerrors.NewError(
fmt.Sprintf("JSON cannot represent value: %v", valueAST),
nil, "", nil, nil, nil)
panic(err)
}
value:=make([]interface{}, len(valueList))
fori, item:=rangevalueList {
value[i] =parseLiteral(item)
}
returnvalue
}
funcparseLiteral(valueAST ast.Value) interface{} {
switchvalueAST.GetKind() {
casekinds.StringValue, kinds.BooleanValue:
returnvalueAST.GetValue()
casekinds.IntValue:
intValue:= (valueAST.GetValue()).(string)
v, _:=strconv.ParseFloat(intValue, 64)
returnvcasekinds.FloatValue:
floatValue:= (valueAST.GetValue()).(string)
v, _:=strconv.ParseFloat(floatValue, 64)
returnvcasekinds.ObjectValue:
returnparseObject(valueAST.GetValue())
casekinds.ListValue:
returnparseList(valueAST.GetValue())
casekinds.NonNull:
returnnilcasekinds.Variable:
varname ast.Nameswitchv:=valueAST.GetValue().(type) {
case*ast.Name:
name=*vcase ast.Name:
name=v
}
err:=gqlerrors.NewError(
fmt.Sprintf("JSON does not support the use of variable: $%s", name.Value),
nil, "", nil, nil, nil)
panic(err)
}
err:=gqlerrors.NewError(
fmt.Sprintf("JSON cannot represent value: %v", valueAST),
nil, "", nil, nil, nil)
panic(err)
}
varJSONScalarType=graphql.NewScalar(graphql.ScalarConfig{
Name: "JSON",
Description: "The `JSON` scalar",
Serialize: func(valueinterface{}) interface{} {
err:=gqlerrors.NewError(
"This method is successfully caught by graphql.Do, and any errors that occur will be added to Result.Errors.",
nil, "", nil, nil, nil)
panic(err)
returnvalue
},
ParseValue: func(valueinterface{}) interface{} {
/*err := gqlerrors.NewError( "graphql.Do does not catch exceptions, and the program crashes directly when an error occurs.", nil, "", nil, nil, nil) panic(err)*/returnvalue
},
// ParseLiteral does not catch exceptions, and the program crashes directly when an error occurs.ParseLiteral: parseLiteral,
})
funcmain() {
schema, err:=graphql.NewSchema(graphql.SchemaConfig{
Query: graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"getData": &graphql.Field{
Type: JSONScalarType,
Args: graphql.FieldConfigArgument{
"input": &graphql.ArgumentConfig{
Type: JSONScalarType,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
returnmap[string]interface{}{
"test": "testValue",
}, nil
},
},
},
}),
})
iferr!=nil {
log.Fatal(err)
}
query:=` query ($input: JSON) { getData(input: {test: $input}) } `result:=graphql.Do(graphql.Params{
Schema: schema,
RequestString: query,
VariableValues: map[string]interface{}{
"input": 89897886,
},
})
b, err:=json.Marshal(result)
iferr!=nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
The text was updated successfully, but these errors were encountered:
When using custom scalar types, it's crucial to provide error feedback to users when issues arise with their submitted data. However, triggering exceptions within the ParseValue and ParseLiteral methods can lead to program crashes when using the graphql.Do method. This prevents the necessary error messages from being delivered to users.
The proposed improvement is to handle exceptions by checking the error object's type when they occur. If the error is created using gqlerrors.Error{}, it signifies that the error object's Message field contains information intended for user feedback, allowing us to capture and return that Message to users. In cases where the error is not created using gqlerrors.Error{}, it can be rethrown as an exception. This approach enhances error handling and ensures that valuable information is communicated to users while avoiding the potential exposure of sensitive information by preventing all exceptions from being exposed to the frontend.
The text was updated successfully, but these errors were encountered: