wundergraph / graphql-go-tools

GraphQL Router / API Gateway framework written in Golang, focussing on correctness, extensibility, and high-performance. Supports Federation v1 & v2, Subscriptions & more.
https://graphql-api-gateway.com
MIT License
683 stars 126 forks source link

Error querying custom integer scalar #454

Closed dchukmasov closed 5 months ago

dchukmasov commented 1 year ago

Hi! I have a GQL schema that defines a custom scalar type

scalar Duration

and this is the implementation of marshaling/unmarshaling using github.com/99designs/gqlgen

// UnmarshalGQL implements the graphql.Unmarshaler interface.
func (ft *Duration) UnmarshalGQL(v interface{}) error {
    var value int64
    switch val := v.(type) {
    case int:
        value = int64(val)
    case int32:
        value = int64(val)
    case int64:
        value = val
    case string:
        intVal, err := strconv.Atoi(val)
        if err != nil {
            return fmt.Errorf("Duration: %w", err)
        }
        value = int64(intVal)
    default:
        return fmt.Errorf("Duration: %w", errTypeUnsupported)
    }

    t := time.Millisecond * time.Duration(value)

    *ft = TreasuryFlowTimeDuration(t)
    return nil
}

// MarshalGQL implements the graphql.Marshaler interface.
func (ft Duration) MarshalGQL(w io.Writer) {
    const base = 10
    conv := time.Duration(ft).Milliseconds()
    s := strconv.FormatInt(conv, base)
    _, _ = w.Write([]byte(s))
}

This works fine when querying the service directly, receiving

"value": 123

But doing query through federation and enginev2 the query fails with an error

"invalid value type 'number' for path /to/my/type, expecting string, got: 0. You can fix this by configuring this field as Int/Float Scalar"

It is fixed if I add strconv.Quote to MarshalGQL method, but in this case the value returned is a string, while I need a number.

I would much appreciate any ideas on the issue. Thanks!

jensneuse commented 1 year ago

When you combine the federated Schema, you have to replace the Duration scalar with Int. This can be done, e.g. by using the ast walker/visitor from graphql-go-tools or graphql.js. Here's an example of how we do it in WunderGraph: https://github.com/wundergraph/wundergraph/blob/a1b82a1204401e538b3341e797e19f8e67b69095/packages/sdk/src/graphql/schema.ts#L147

The execution engine of graphql-go-tools doesn't understand the encoding of custom scalars. So, to support custom scalars, you have to rewrite them into the best fitting GraphQL/JSON scalar, e.g. Float, Int, Boolean or String.