Search code examples
javascriptgogo-gin

How to send information in frontend with POST to backend with Gin and Go


I normally send data within forms, and never had any problem, but now I need to send the data with JavaScript, and I am not able to read it in the backend.

My main.go file:

package main

import (
    "encoding/json"
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    // We create the instance for Gin
    r := gin.Default()

    // Path to the static files. /static is rendered in the HTML and /media is the link to the path to the  images, svg, css.. the static files
    r.StaticFS("/static", http.Dir("../media"))

    // Path to the HTML templates. * is a wildcard
    r.LoadHTMLGlob("*.html")

    r.NoRoute(renderHome)
    // This get executed when the users gets into our website in the home domain ("/")
    r.GET("/", renderHome)
    r.POST("/", getData)
    r.Run(":8080")
}

func renderHome(c *gin.Context) {
    c.HTML(http.StatusOK, "my-html.html", gin.H{})
}

func getData(c *gin.Context) {
    formData := &struct {
        Name string `json:"mydata"  binding:"required" `
    }{}
    // Validation (with Gin)
    if err := c.Bind(formData); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        fmt.Print(err)
        return
    }
    fmt.Println("formData: ", formData.Name)

    dec := json.NewDecoder(c.Request.Body)
    fmt.Println("Decooder: ", dec)

    dec.Decode(formData)
    fmt.Println("formData: ", formData.Name)

    p := c.PostForm("mydata")
    fmt.Println("Params: ", p)
    p = c.Params.ByName("mydata")
    fmt.Println("Params: ", p)
    p, _ = c.Params.Get("mydata")
    fmt.Println("Get: ", p)

    fmt.Println("Body: ", c.Request.Body)
}

My HTML file, located in the same directory:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body onload="afterLoad()" style="background-color: pink">
    <script>
      async function postData(url = "", data = {}) {
        // Opciones por defecto estan marcadas con un *
        const response = await fetch(url, {
          method: "POST",
          mode: "cors",
          cache: "no-cache",
          credentials: "same-origin",
          headers: {
            // "Content-Type": "application/json",
            "Content-Type": "application/x-www-form-urlencoded",
          },
          redirect: "follow",
          referrerPolicy: "no-referrer",
          body: JSON.stringify(data),
        });
        return response.json(); // parses JSON response into native JavaScript objects
      }

      function afterLoad() {
        postData("/", { mydata: 42 }).then((data) => {
          console.log(data); // JSON data parsed by `data.json()` call
        });
      }
    </script>
  </body>
</html>

I tried to interchange the headers from application/json to application/x-www-form-urlencoded but no luck. The answer I get in the console after reloading the page in the browser (and the method afterLoad() from JavaScript gets executed) is:

formData:  
Decooder:  &{0xc0002b7580 [] {[] 0 0 {<nil> false [] <nil> 0} {<nil> []} <nil> false false} 0 0 {<nil> false [] <nil> 0} <nil> 0 []}
formData:  
Params:  
Params:  
Get:

This data is printed from the getData() func in main.go file. What I am doing wrong to not be able to get the data?


Solution

  • I see two problems. First, formData is a pointer to struct and when you use decode you get the address of something that's already an address. Second, your struct doesn't have a json tag with mydata, just a form tag, which is not enough for json.Decode to map the json attribute to the struct attribute. Change the form tag for a json tag