handling - json to interface golang
Manejo de solicitud de publicaciĆ³n de JSON en Go (4)
Entonces tengo lo siguiente, que parece increíblemente intrépido, y me he estado pensando a mí mismo que Go tiene bibliotecas mejor diseñadas que esto, pero no puedo encontrar un ejemplo de Go manejando una solicitud POST de datos JSON. Todos son formularios POSTs.
Aquí hay un ejemplo de solicitud: curl -X POST -d "{/"test/": /"that/"}" http://localhost:8082/test
Y aquí está el código, con los registros incrustados:
package main
import (
"encoding/json"
"log"
"net/http"
)
type test_struct struct {
Test string
}
func test(rw http.ResponseWriter, req *http.Request) {
req.ParseForm()
log.Println(req.Form)
//LOG: map[{"test": "that"}:[]]
var t test_struct
for key, _ := range req.Form {
log.Println(key)
//LOG: {"test": "that"}
err := json.Unmarshal([]byte(key), &t)
if err != nil {
log.Println(err.Error())
}
}
log.Println(t.Test)
//LOG: that
}
func main() {
http.HandleFunc("/test", test)
log.Fatal(http.ListenAndServe(":8082", nil))
}
Tiene que haber una mejor manera, ¿verdad? Simplemente estoy perplejo al encontrar lo que podría ser la mejor práctica.
(Go también se conoce como Golang para los motores de búsqueda, y se menciona aquí para que otros puedan encontrarlo).
Encontré el siguiente ejemplo de la documentación realmente útil (fuente here ).
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `
{"Name": "Ed", "Text": "Knock knock."}
{"Name": "Sam", "Text": "Who''s there?"}
{"Name": "Ed", "Text": "Go fmt."}
{"Name": "Sam", "Text": "Go fmt who?"}
{"Name": "Ed", "Text": "Go fmt yourself!"}
`
type Message struct {
Name, Text string
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s/n", m.Name, m.Text)
}
}
La clave aquí es que el OP estaba buscando decodificar
type test_struct struct {
Test string
}
... en cuyo caso, descartaríamos la const jsonStream
y reemplazaríamos la estructura de Message
con test_struct
:
func test(rw http.ResponseWriter, req *http.Request) {
dec := json.NewDecoder(req.Body)
for {
var t test_struct
if err := dec.Decode(&t); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
log.Printf("%s/n", t.Test)
}
}
Actualización : También agregaría que esta publicación proporciona información excelente sobre cómo responder con JSON también. El autor explica las struct tags
, de las que no tenía conocimiento.
Como JSON normalmente no se ve como {"Test": "test", "SomeKey": "SomeVal"}
, sino más bien {"test": "test", "somekey": "some value"}
, puede reestructurar su estructura así:
type test_struct struct {
Test string `json:"test"`
SomeKey string `json:"some-key"`
}
... y ahora su manejador analizará JSON usando "some-key" en lugar de "SomeKey" (que usará internamente).
Me estaba volviendo loco con este problema exacto. Mi JSON Marshaller y Unmarshaller no estaban poblando mi estructura Go. Luego encontré la solución en https://eager.io/blog/go-and-json :
"Al igual que con todas las estructuras en Go, es importante recordar que solo los campos con una primera letra mayúscula son visibles para programas externos como el JSON Marshaller".
Después de eso, mi Marshaller y Unmarshaller funcionaron perfectamente.
Necesitas leer desde req.Body
. El método ParseForm
está leyendo desde req.Body
y luego req.Body
en formato codificado HTTP estándar. Lo que quieres es leer el cuerpo y analizarlo en formato JSON.
Aquí está su código actualizado.
package main
import (
"encoding/json"
"log"
"net/http"
"io/ioutil"
)
type test_struct struct {
Test string
}
func test(rw http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
panic(err)
}
log.Println(string(body))
var t test_struct
err = json.Unmarshal(body, &t)
if err != nil {
panic(err)
}
log.Println(t.Test)
}
func main() {
http.HandleFunc("/test", test)
log.Fatal(http.ListenAndServe(":8082", nil))
}
Utilice json.Decoder
lugar de json.Unmarshal
.
func test(rw http.ResponseWriter, req *http.Request) {
decoder := json.NewDecoder(req.Body)
var t test_struct
err := decoder.Decode(&t)
if err != nil {
panic(err)
}
log.Println(t.Test)
}