Search code examples
gographqlvue-apollo

Vue Apollo: variables are not added to graphql query, or I am not correctly accepting them on the backend (Golang)


I cannot seem to get variables in a graphql query made with apollo into the query body to be accepted into backend server.

I have a simple vue frontend and go backend. In a vue-component I have the following query:

apollo: {
    entry: {
      query: gql`
        query variables($userID: Int){
          entries(userID: $userID) {
            id,
            value,
            timeStamp
          }
        }
      `,
      variables() {
        return {
          userID: 2
        }
      },

      update: data => data,
    }
  }
}

On my go backend I nave the handler function for all POST requests

// GraphQL returns an http.HandlerFunc for our /graphql endpoint
func (s *Server) GraphQL() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        //Allow CORS here By * or specific origin
        w.Header().Set("Access-Control-Allow-Origin", "*")

        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
        // Check to ensure query was provided in the request body
        if r.Body == nil {
            http.Error(w, "Must provide graphql query in request body", 400)
            return
        }

        var rBody reqBody
        // Decode the request body into rBody
        err := json.NewDecoder(r.Body).Decode(&rBody)
        if err != nil {
            http.Error(w, "Error parsing JSON request body", 400)
        }

        fmt.Println(rBody.Query)

        // Execute graphql query
        result := gql.ExecuteQuery(rBody.Query, *s.GqlSchema)

        // render.JSON comes from the chi/render package and handles
        // marshalling to json, automatically escaping HTML and setting
        // the Content-Type as application/json.
        render.JSON(w, r, result)
    }
}

When I run the query, I am returned {"entries" : null}. When I print out the query that was sent to my go server, I get the following:

query variables($userID: Int) {
  entries(userID: $userID) {
    id
    value
    timeStamp
    __typename
  }
}

In line 2 of this I would hope to see entries(userID: 2). Indeed, if I remove the variables from my query made in vue, and hardcode the userID in the query, everything works.

I checked to make sure the variable is being sent in someway, which if I look at the POST request made it has the following in the parameters:

operationName   variables
query   query variables($userID: Int) { entries(userID: $userID) { id value timeStamp __typename } }
variables   {…}
userID  2

Am I not accepting the data correctly on my backend, as the variable userID is being sent in the POST request?

Solution: Thanks to @cgcgbcbc for the solution. My reqBody struct was the following:

type reqBody struct {
    Query     string                 `json:"query"`
}

When it should be:

type reqBody struct {
    Query     string                 `json:"query"`
    Variables map[string]interface{} `json:"variables"`
}

Then I just needed to pass rBody.Variables to my ExecuteQuery function as in his solution.


Solution

  • For your question, the data receiving in your backend is correct, the query itself does not contain the query parameter, the query parameter is sent via variables key.

    The response issue is this line result := gql.ExecuteQuery(rBody.Query, *s.GqlSchema). variables from the request body need also be passed to ExecuteQuery. An example implementation using graphql-go/graphql Do function can be

    func executeQuery(query string, schema graphql.Schema, variables map[string]interface{}) *graphql.Result {
        result := graphql.Do(graphql.Params{
            Schema:        schema,
            RequestString: query,
            VariableValues: variables
        })
        if len(result.Errors) > 0 {
            fmt.Printf("errors: %v", result.Errors)
        }
        return result
    }
    

    And an example of type reqBody can be

    type reqBody struct {
        Query string
        Variables map[string]interface{}
    }
    

    Then json.NewDecoder(r.Body).Decode(&rBody) will automatically set Query and Variables