graphql-go / graphql

An implementation of GraphQL for Go / Golang
MIT License
9.87k stars 839 forks source link

Modifying Context during a resolve function to transfer data down a tree #156

Open bbuck opened 8 years ago

bbuck commented 8 years ago

If, for example, you had some query like:

first {
  second {
    third {
      a
      b
      c
    }
  }
}

And during the resolve function for first you want to carry over some data for third to use during resolution you might think you could do something like:

params.Context = context.WithValue(params.Context, someContextKey, someValue)

But of course this won't work at all. I think it might be worth finding a way to allow something like this to happen, otherwise it would seem that third has to always be built in such a way that it can't know anything about the tree it's being requested from other than through arguments (and if you're having to repeat the same argument per tier that might become problematic).

I'm not sure if the graphql-js "root value" solution allows this to happen (and if it doesn't, then I suppose there is no reason for this project too) it just seems useful.

What are your thoughts about this?

axetroy commented 6 years ago

graphql-js support add some property on context. so you can transfer data down a tree.

Can you found a way for this?

axetroy commented 6 years ago

I found the way to transfer data down a tree, but It is too tedious.

Query With this options

        result := graphql.Do(graphql.Params{
            Schema:         ql.Schema,
            RequestString:  graphQuery.Query,
            Context:        context,
            VariableValues: graphQuery.Variables,
            OperationName:  graphQuery.OperationName,
            RootObject: map[string]interface{}{
                "context":  context,
            },
        })

The parent resolve

            Resolve: func(p graphql.ResolveParams) (interface{}, error) {

                rootValue := p.Info.RootValue.(map[string]interface{})
                ctx := rootValue["context"].(*gin.Context)

                ctx.Request = ctx.Request.WithContext(context.WithValue(ctx.Request.Context(), "testKey", "testValue"))

                return meFields, nil
            },

The child resolve, Get the the data from parent

            Resolve: func(p graphql.ResolveParams) (interface{}, error) {

                rootValue := p.Info.RootValue.(map[string]interface{})
                ctx := rootValue["context"].(*gin.Context)

                c := ctx.Request.Context()

                fmt.Println(c.Value("testKey"))
            },
lukaspj commented 5 years ago

Is this thread-safe? I used root value naïvely with just key-value pairs of type string, but it did not work in a concurrent pattern given the following case:

first {
   second {
      a
      b
   }
   third {
      c
      d
   }
}

Because if I changed the root-value in second and third then it would be borked in a and b. I think the root-value can only be used in a concurrent context, when the changes to the root-value is not concurrent.