GraphQL请求的JSON请求体无法解码。

huangapple go评论134阅读模式
英文:

GraphQL request json request body could not be decoded:

问题

我对GraphQL还不太熟悉,所以我查看了我的Postman请求。
这是原始的Postman请求。

  1. 请求头
  2. Content-Type: application/json
  3. User-Agent: PostmanRuntime/7.29.2
  4. Accept: */*
  5. Cache-Control: no-cache
  6. Postman-Token: e3239924-6e8a-48b9-bc03-3216ea6da544
  7. Host: localhost:4000
  8. Accept-Encoding: gzip, deflate, br
  9. Connection: keep-alive
  10. Content-Length: 94
  11. 请求体
  12. query: "query {
  13. getTodo(todoId:3) {
  14. id
  15. text
  16. done
  17. }
  18. }"

我尝试了以下代码

  1. var url = "http://localhost:4000/query"
  2. func TestGetTodoByID(t *testing.T) {
  3. jsonData := `query {
  4. getTodo(todoId:3) {
  5. id
  6. text
  7. done
  8. }
  9. }`
  10. fmt.Println(jsonData)
  11. request, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(jsonData)))
  12. request.Header.Set("Content-Type", "application/json")
  13. request.Header.Set("Content-Length", fmt.Sprint(len(jsonData)))
  14. client := &http.Client{Timeout: time.Second * 10}
  15. response, err := client.Do(request)
  16. defer response.Body.Close()
  17. if err != nil {
  18. fmt.Printf("The HTTP request failed with error %s\n", err)
  19. }
  20. data, err := io.ReadAll(response.Body)
  21. if err != nil {
  22. fmt.Printf("Error reading response with error %s\n", err)
  23. }
  24. responseBody := string(data)
  25. if status := response.StatusCode; status != http.StatusOK {
  26. t.Errorf("handler returned wrong status code: got %v want %v",
  27. status, http.StatusOK)
  28. }
  29. expected := `{
  30. "data": {
  31. "getTodo": {
  32. "id": 3,
  33. "text": "qwert333 hello",
  34. "done": true
  35. }
  36. }
  37. }`
  38. if responseBody != expected {
  39. t.Errorf("handler returned unexpected body: got %v want %v",
  40. responseBody, expected)
  41. }
  42. }

然后我得到了以下错误:

  1. api_test.go:41: handler returned wrong status code: got 400 want 200
  2. api_test.go:54: handler returned unexpected body: got {"errors":[{"message":"json request body could not be decoded: invalid character 'q' looking for beginning of value body:query {\n getTodo(todoId:3) {\n id\n text\n done\n }\n}"}],"data":null} want {

然后我也尝试了在Postman控制台中找到的代码

  1. jsonData := `"query":"query {
  2. getTodo(todoId:3) {
  3. id
  4. text
  5. done
  6. }
  7. }"`

这给了我一个稍微不同的错误

  1. api_test.go:41: handler returned wrong status code: got 400 want 200
  2. api_test.go:54: handler returned unexpected body: got {"errors":[{"message":"json request body could not be decoded: json: cannot unmarshal string into Go value of type graphql.RawParams body:\"query\":\"query {\n getTodo(todoId:3) {\n id\n text\n done\n }\n}\""}],"data":null} want {

有什么想法吗?

英文:

I am new to GraphQL so I looked at my Postman request.
This is the raw Postman request.

  1. Request Headers
  2. Content-Type: application/json
  3. User-Agent: PostmanRuntime/7.29.2
  4. Accept: */*
  5. Cache-Control: no-cache
  6. Postman-Token: e3239924-6e8a-48b9-bc03-3216ea6da544
  7. Host: localhost:4000
  8. Accept-Encoding: gzip, deflate, br
  9. Connection: keep-alive
  10. Content-Length: 94
  11. Request Body
  12. query: "query {
  13. getTodo(todoId:3) {
  14. id
  15. text
  16. done
  17. }
  18. }"

I tried the following

  1. var url = "http://localhost:4000/query"
  2. func TestGetTodoByID(t *testing.T) {
  3. jsonData := `query {
  4. getTodo(todoId:3) {
  5. id
  6. text
  7. done
  8. }
  9. }`
  10. fmt.Println(jsonData)
  11. request, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(jsonData)))
  12. request.Header.Set("Content-Type", "application/json")
  13. request.Header.Set("Content-Length", fmt.Sprint(len(jsonData)))
  14. client := &http.Client{Timeout: time.Second * 10}
  15. response, err := client.Do(request)
  16. defer response.Body.Close()
  17. if err != nil {
  18. fmt.Printf("The HTTP request failed with error %s\n", err)
  19. }
  20. data, err := io.ReadAll(response.Body)
  21. if err != nil {
  22. fmt.Printf("Error reading response with error %s\n", err)
  23. }
  24. responseBody := string(data)
  25. if status := response.StatusCode; status != http.StatusOK {
  26. t.Errorf("handler returned wrong status code: got %v want %v",
  27. status, http.StatusOK)
  28. }
  29. expected := `{
  30. "data": {
  31. "getTodo": {
  32. "id": 3,
  33. "text": "qwert333 hello",
  34. "done": true
  35. }
  36. }
  37. }`
  38. if responseBody != expected {
  39. t.Errorf("handler returned unexpected body: got %v want %v",
  40. responseBody, expected)
  41. }
  42. }

Then I got the following error:

  1. api_test.go:41: handler returned wrong status code: got 400 want 200
  2. api_test.go:54: handler returned unexpected body: got {"errors":[{"message":"json request body could not be decoded: invalid character 'q' looking for beginning of value body:query {\n getTodo(todoId:3) {\n id\n text\n done\n }\n}"}],"data":null} want {

Then I also tried exactly what I found in the Postman console

  1. jsonData := `"query":"query {
  2. getTodo(todoId:3) {
  3. id
  4. text
  5. done
  6. }
  7. }"`

This gave me a slightly different error

  1. api_test.go:41: handler returned wrong status code: got 400 want 200
  2. api_test.go:54: handler returned unexpected body: got {"errors":[{"message":"json request body could not be decoded: json: cannot unmarshal string into Go value of type graphql.RawParams body:\"query\":\"query {\n getTodo(todoId:3) {\n id\n text\n done\n }\n}\""}],"data":null} want {

Any ideas?

答案1

得分: 1

标准的GraphQL JSON格式实际上是一个JSON对象。在Go语言环境中,最简单的方法是使用encoding/json包中的结构体进行创建。(你可以寻找一个专门的GraphQL客户端包,其中已经预定义了这个结构体。)

例如,你可以为该结构体创建一个最简形式的结构体:

  1. type GraphQLRequest struct{
  2. Query string `json:"query"`
  3. Variables map[string]interface{} `json:"variables,omitempty"`
  4. }

然后创建该结构体的实例并进行序列化:

  1. query := `query GetTodo($id: ID!) {
  2. getTodo(todoId: $id) { id, name, done }
  3. }`
  4. request := GraphQLRequest{
  5. Query: query,
  6. Variables: map[string]interface{}{
  7. "id": 3,
  8. }
  9. }
  10. jsonData, err := json.Marshal(request)
  11. if (err != nil) {
  12. panic(err) // 或者以其他方式处理错误
  13. }
  14. request, err := http.NewRequest("POST", url, jsonData)
  15. ...

你可能会发现,将响应数据使用json.Unmarshal()解析为一个具有标准格式的结构体同样很有用,其中Data字段与你的查询形状相匹配。

英文:

The standard GraphQL JSON format is actually a JSON object. In a Go context, the easiest way to create this is with a structure annotated for the encoding/json package. (You may go looking for a dedicated GraphQL client package that has this structure predefined.)

So for example you might create a structure for the minimal form of that structure

  1. type GraphQLRequest struct{
  2. Query string `json:"query"`
  3. Variables map[string]interface{} `json:"variables,omitempty"`
  4. }

and then create an instance of that structure and serialize it

  1. query := `query GetTodo($id: ID!) {
  2. getTodo(todoId: $id) { id, name, done }
  3. }`
  4. request := GraphQLRequest{
  5. Query: query,
  6. Variables: map[string]interface{}{
  7. "id": 3,
  8. }
  9. }
  10. jsonData, err := json.Marshal(request)
  11. if (err != nil) {
  12. panic(err) // or handle it however you would otherwise
  13. }
  14. request, err := http.NewRequest("POST", url, jsonData)
  15. ...

You may find it similarly useful to json.Unmarshal() the response data into a structure that has the standard format, with a Data field matching the shape of your query.

huangapple
  • 本文由 发表于 2022年12月15日 04:13:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/74803721.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定