graphql-go / graphql

An implementation of GraphQL for Go / Golang
MIT License
9.94k stars 841 forks source link

Resolver is not extracting nested structs #610

Open Moranilt opened 3 years ago

Moranilt commented 3 years ago

I'm using last version of graphql v0.7.9

I have query "users" which should return a list of users:

image

QueryType: image

structs: image

pgsql is *sqlx.DB

As you can see I'm using nested struct UserInput for UserType. Actually sqlx is binding values to it correctly and when I'm calling fmt.Println(user[0].First_name) it works good, but for graphql - not!

image

When I'm not using nested structs - it works good. Seems like a bug.

asif-mahmud commented 3 years ago

i can confirm this too. i used something like this and it didnt work -

type Model struct {
    ID int64
    CreatedAt time.Time
    UpdatedAt time.Time
}
type User struct {
    Model
    Name string
    Email string
}

So when i returned a User value, the graphql parser didn't parse the fields from Model.

bhoriuchi commented 3 years ago

try converting your user array to an []map[string]interface{} and see if that resolves it. The field selection might be having a hard time with custom structs?

Moranilt commented 3 years ago

@bhoriuchi but why should I use untyped interface? When the laguage says that I should use structs to avoid errors. It's bad idea to use []map[string]interface{}.

bhoriuchi commented 3 years ago

I said try it. It doesn't mean that should be your final solution but it may help figure out where the issue is.

The reason I suggest converting it is because your struct fields are capitalized and your selections are not, so how is the query expected to select the right field when the field names are not matching? Using the json.Marshal function your json tags will be respected and likely map properly.

asif-mahmud commented 3 years ago

it will work, i used map of interfaces, it worked. but just doesn't work for nested structs like the little example.

Best wishes - Asif Mahmud Shimon

On Sun, Sep 5, 2021 at 8:49 PM Branden Horiuchi @.***> wrote:

I said try it. It doesn't mean that should be your final solution but it may help figure out where the issue is

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/graphql-go/graphql/issues/610#issuecomment-913168352, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABLQLUSWIHDPSCI63TVJYEDUAN7PLANCNFSM5CDGX2UQ .

Moranilt commented 3 years ago

I said try it. It doesn't mean that should be your final solution but it may help figure out where the issue is.

The reason I suggest converting it is because your struct fields are capitalized and your selections are not, so how is the query expected to select the right field when the field names are not matching? Using the json.Marshal function your json tags will be respected and likely map properly.

I'm sorry. yeah, it will work, i knew it. But as @asif-mahmud said it doesn't work for nested structs and looks like this is a bug. I was expected to use nested structs.

Moranilt commented 3 years ago

Exactly sqlx.Select is buinding good nested structs. But when I'm using this struct in graphql-resolver to return user it's not returning nested properties from struct user(in my case).

bhoriuchi commented 3 years ago

I think the package just doesn't work that way. The executeSubFields (https://github.com/graphql-go/graphql/blob/master/executor.go#L297) function builds a map[string]interface{} from the resolvers. Since go is strongly typed I'm not sure how its expected to return your expected struct. GraphQL traverses the type and resolves each field individually and builds a resulting object from that. This is how the js reference implementation works. the only thing you can probably do here is add custom resolvers on to each of the fields in your nested struct that return the value of that field but your result from a query will still likely be a map[string]interface{}

asif-mahmud commented 3 years ago

i miss generics :D

Best wishes - Asif Mahmud Shimon

On Tue, Sep 7, 2021 at 6:14 AM Branden Horiuchi @.***> wrote:

I think the package just doesn't work that way. The executeSubFields function builds a map[string]interface{} from the resolvers. Since go is strongly typed I'm not sure how its expected to return your expected struct. GraphQL traverses the type and resolves each field individually and builds a resulting object from that. This is how the js reference implementation works. the only thing you can probably do here is add custom resolvers on to each of the fields in your nested struct that return the value of that field.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/graphql-go/graphql/issues/610#issuecomment-913907723, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABLQLUUL4PRIRUE2JR4LOLLUAVKP5ANCNFSM5CDGX2UQ .

Moranilt commented 3 years ago

I think the package just doesn't work that way. The executeSubFields (https://github.com/graphql-go/graphql/blob/master/executor.go#L297) function builds a map[string]interface{} from the resolvers. Since go is strongly typed I'm not sure how its expected to return your expected struct. GraphQL traverses the type and resolves each field individually and builds a resulting object from that. This is how the js reference implementation works. the only thing you can probably do here is add custom resolvers on to each of the fields in your nested struct that return the value of that field but your result from a query will still likely be a map[string]interface{}

Yeah, probably is the best way to add my own resolver, but we are losing strict return value. It will be always map[string]interface{}. It's not gorgeous solution.

noragem commented 3 years ago

I have the same issue. Is there any way to fix it?