json: 无法将对象解组为类型为 []*main.Config 的 Go 值。

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

json: cannot unmarshal object into Go value of type []*main.Config

问题

我是你的中文翻译助手,以下是你提供的代码的翻译:

package main

import (
	"errors"
	"github.com/gorilla/mux"
	"mime"
	"net/http"
)

type Config struct {
	Id      string            `json:"id"`
	entries map[string]string `json:"entries"`
}

type postServer struct {
	data map[string][]*Config
}

func (ts *postServer) createPostHandler(w http.ResponseWriter, req *http.Request) {
	contentType := req.Header.Get("Content-Type")
	mediatype, _, err := mime.ParseMediaType(contentType)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if mediatype != "application/json" {
		err := errors.New("Expect application/json Content-Type")
		http.Error(w, err.Error(), http.StatusUnsupportedMediaType)
		return
	}

	rt, err := decodeBody(req.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	id := createId()
	ts.data[id] = rt
	renderJSON(w, rt)
}

func (ts *postServer) getAllHandler(w http.ResponseWriter, req *http.Request) {
	allTasks := []*Config{}
	for _, v := range ts.data {
		allTasks = append(allTasks, v...)
	}

	renderJSON(w, allTasks)
}

func (ts *postServer) getPostHandler(w http.ResponseWriter, req *http.Request) {
	id := mux.Vars(req)["id"]
	task, ok := ts.data[id]
	if !ok {
		err := errors.New("key not found")
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	renderJSON(w, task)
}

func (ts *postServer) delPostHandler(w http.ResponseWriter, req *http.Request) {
	id := mux.Vars(req)["id"]
	if v, ok := ts.data[id]; ok {
		delete(ts.data, id)
		renderJSON(w, v)
	} else {
		err := errors.New("key not found")
		http.Error(w, err.Error(), http.StatusNotFound)
	}
}

func decodeBody(r io.Reader) ([]*Config, error) {
	dec := json.NewDecoder(r)
	dec.DisallowUnknownFields()

	var rt []*Config
	if err := dec.Decode(&rt); err != nil {
		return nil, err
	}
	return rt, nil
}

func renderJSON(w http.ResponseWriter, v interface{}) {
	js, err := json.Marshal(v)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

func createId() string {
	return uuid.New().String()
}

func main() {
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)

	router := mux.NewRouter()
	router.StrictSlash(true)

	server := postServer{
		data: map[string][]*Config{},
	}
	router.HandleFunc("/config/", server.createPostHandler).Methods("POST")
	router.HandleFunc("/configs/", server.getAllHandler).Methods("GET")
	router.HandleFunc("/config/{id}/", server.getPostHandler).Methods("GET")
	router.HandleFunc("/config/{id}/", server.delPostHandler).Methods("DELETE")

	// start server
	srv := &http.Server{Addr: "0.0.0.0:8000", Handler: router}
	go func() {
		log.Println("server starting")
		if err := srv.ListenAndServe(); err != nil {
			if err != http.ErrServerClosed {
				log.Fatal(err)
			}
		}
	}()

	<-quit

	log.Println("service shutting down ...")

	// gracefully stop server
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal(err)
	}
	log.Println("server stopped")
}

你在Postman中发送的JSON数据是:

{
	"entries": ["hello", "world"]
}

你在decodeBody函数中遇到的错误是:

json: cannot unmarshal object into Go value of type []*main.Config

你想知道问题出在哪里,可能是你发送了错误的JSON数据,或者在decodeBody函数中做错了什么。你在decodeBody函数中的var rt []*Config前面需要添加[],否则它将无法工作。

希望这可以帮助你解决问题!

英文:

I'm new to golang and json, we are using gorilla mux library and I'd like to do a post request in postman. In config struct entries needs to be a map like that and in post server I need to have an array of *Config in postServer struct. I have 3 go files.
Service.go file is this:

package main
import (
&quot;errors&quot;
&quot;github.com/gorilla/mux&quot;
&quot;mime&quot;
&quot;net/http&quot;
)
type Config struct {
Id      string            `json:&quot;id&quot;`
entries map[string]string `json:&quot;entries&quot;`
}
type postServer struct {
data map[string][]*Config
}
func (ts *postServer) createPostHandler(w http.ResponseWriter, req *http.Request) {
contentType := req.Header.Get(&quot;Content-Type&quot;)
mediatype, _, err := mime.ParseMediaType(contentType)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if mediatype != &quot;application/json&quot; {
err := errors.New(&quot;Expect application/json Content-Type&quot;)
http.Error(w, err.Error(), http.StatusUnsupportedMediaType)
return
}
rt, err := decodeBody(req.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
id := createId()
ts.data[id] = rt
renderJSON(w, rt)
}
func (ts *postServer) getAllHandler(w http.ResponseWriter, req *http.Request) {
allTasks := []*Config{}
for _, v := range ts.data {
allTasks = append(allTasks, v...)
}
renderJSON(w, allTasks)
}
func (ts *postServer) getPostHandler(w http.ResponseWriter, req *http.Request) {
id := mux.Vars(req)[&quot;id&quot;]
task, ok := ts.data[id]
if !ok {
err := errors.New(&quot;key not found&quot;)
http.Error(w, err.Error(), http.StatusNotFound)
return
}
renderJSON(w, task)
}
func (ts *postServer) delPostHandler(w http.ResponseWriter, req *http.Request) {
id := mux.Vars(req)[&quot;id&quot;]
if v, ok := ts.data[id]; ok {
delete(ts.data, id)
renderJSON(w, v)
} else {
err := errors.New(&quot;key not found&quot;)
http.Error(w, err.Error(), http.StatusNotFound)
}
}

I wanted to test createPostHandler.
Then I have helper.go file where I decoded json into go and rendered into json:

package main
import (
&quot;encoding/json&quot;
&quot;github.com/google/uuid&quot;
&quot;io&quot;
&quot;net/http&quot;
)
func decodeBody(r io.Reader) ([]*Config, error) {
dec := json.NewDecoder(r)
dec.DisallowUnknownFields()
var rt []*Config
if err := dec.Decode(&amp;rt); err != nil {
return nil, err
}
return rt, nil
}
func renderJSON(w http.ResponseWriter, v interface{}) {
js, err := json.Marshal(v)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set(&quot;Content-Type&quot;, &quot;application/json&quot;)
w.Write(js)
}
func createId() string {
return uuid.New().String()
}

and the last one go file is main.go where I have this:

package main
import (
&quot;context&quot;
&quot;github.com/gorilla/mux&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;os&quot;
&quot;os/signal&quot;
&quot;syscall&quot;
&quot;time&quot;
)
func main() {
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
router := mux.NewRouter()
router.StrictSlash(true)
server := postServer{
data: map[string][]*Config{},
}
router.HandleFunc(&quot;/config/&quot;, server.createPostHandler).Methods(&quot;POST&quot;)
router.HandleFunc(&quot;/configs/&quot;, server.getAllHandler).Methods(&quot;GET&quot;)
router.HandleFunc(&quot;/config/{id}/&quot;, server.getPostHandler).Methods(&quot;GET&quot;)
router.HandleFunc(&quot;/config/{id}/&quot;, server.delPostHandler).Methods(&quot;DELETE&quot;)
// start server
srv := &amp;http.Server{Addr: &quot;0.0.0.0:8000&quot;, Handler: router}
go func() {
log.Println(&quot;server starting&quot;)
if err := srv.ListenAndServe(); err != nil {
if err != http.ErrServerClosed {
log.Fatal(err)
}
}
}()
&lt;-quit
log.Println(&quot;service shutting down ...&quot;)
// gracefully stop server
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal(err)
}
log.Println(&quot;server stopped&quot;)
}

And JSON whad I did send is this:

{
&quot;entries&quot;:[&quot;hello&quot;, &quot;world&quot;]
}

And error what I'm getting in postman is this:

json: cannot unmarshal object into Go value of type []*main.Config

I don't know what is a problem, maybe I'm sending wrong json or I just did something wrong in decodeBody, I needed to add [] in decodeBody in var rt []*Config because it wouldn't work otherwise.
Can someone help me to fix this please?

答案1

得分: 2

这是一个示例,展示了如何定义一个名为Config的结构体,你可以将样本JSON解析到其中。

编辑:字段entries已更改为map。

你可以在Playground上进行测试。

package main

import (
	"encoding/json"
	"fmt"
)

type Config struct {
	Id      string            `json:"id"`
	Entries map[string]string `json:"entries"`
}

func main() {
	str := `[{"id":"42", "entries":{"hello": "world"}}]`
	var tmp []Config
	err := json.Unmarshal([]byte(str), &tmp)
	if err != nil {
		fmt.Printf("error: %v", err)
	}
	var rt []*Config
	for _, c := range tmp {
		rt = append(rt, &c)
	}
	for _, c := range rt {
		for k, v := range c.Entries {
			fmt.Printf("id=%s key=%s value=%s\n", c.Id, k, v)
		}
	}
}

希望对你有帮助!

英文:

This is an example of how you can define a struct Config that you can parse your sample JSON into.

EDIT: field entries changed to map.

You can play with it on Playground.

package main
import (
&quot;encoding/json&quot;
&quot;fmt&quot;
)
type Config struct {
Id      string            `json:&quot;id&quot;`
Entries map[string]string `json:&quot;entries&quot;`
}
func main() {
str := `[{&quot;id&quot;:&quot;42&quot;, &quot;entries&quot;:{&quot;hello&quot;: &quot;world&quot;}}]`
var tmp []Config
err := json.Unmarshal([]byte(str), &amp;tmp)
if err != nil {
fmt.Printf(&quot;error: %v&quot;, err)
}
var rt []*Config
for _, c := range tmp {
rt = append(rt, &amp;c)
}
for _, c := range rt {
for k, v := range c.Entries {
fmt.Printf(&quot;id=%s key=%s value=%s\n&quot;, c.Id, k, v)
}
}
}

huangapple
  • 本文由 发表于 2022年4月30日 21:14:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/72068828.html
匿名

发表评论

匿名网友

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

确定