返回不同类型的JSON结构,动态地?

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

Returning JSON structs of different types, dynamically?

问题

我正在玩Go,并且在将其他语言中的“继承”设计适应其结构时遇到了一些问题。我以OCaml和其他一些具有类似结构的语言进行编码,但我感到困惑。由于没有类型继承,使用共享结构从不同的位置返回JSON变得有点奇怪。

我必须根据需要递归地遍历输入数据,以构建一个要响应的单个JSON对象。

举个例子:

{
    "appVersion": "1.0.0",
    "messageStatus": "received"
}

和:

{
    "appVersion": "1.0.0",
    "uploadStatus": "received"
}

到目前为止,我在Go中找到的唯一方法是将包含"appVersion"的基本结构复制并粘贴到两个独立的输出生成函数中,但我不想这样做,因为我不想维护相同的代码两次。

以下是我试图解决这个问题的地方:

type JSONResponse struct {
    appVersion string
}
type MessageJSONResponse struct {
    JSONResponse
    messageStatus string
}
type UploadJSONResponse struct {
    JSONResponse
    uploadStatus string
}

然后:

type Message struct {
    formattingVersion *int
}

func NewMessageObject(r *http.Request) (bool, *MessageJSONResponse) {
    message := new(Message)

    if (true) {
        // #TODO: INSERT LOGIC HERE!
        *message.formattingVersion = 2;
    }

    if (message.formattingVersion != nil) {
        response := new(MessageJSONResponse)
        response.messageStatus = "OK";

        return false, errorResponse;
    }

    return true, nil;
}

还有:

func init() {
    http.Handle("/endpoints/message", JSONResponseHandler(messageHandler));
}

func JSONResponseHandler(h func (w http.ResponseWriter, r *http.Request) interface {}) http.Handler {
    // #TODO - convert `JSONResponse` into actual JSON or output JSON Error!
}

func messageHandler(w http.ResponseWriter, r *http.Request) JSONResponse { // #BROKEN TYPES?
    hasError, messageResponse := NewMessageObject(r);
    if (hasError || messageResponse==nil) { return nil } // #TODO
    ////

    // #TODO ... more message things.

    return messageResponse;
}

这种方法(对于任何代码错误,我很抱歉,今天真的很长,我要去睡觉了)不起作用,因为为了传递不同的返回值...类型不能改变等等。

**JSONResponseHandler**包装方法在我的端上实际上是有效的,但由于类型的变化,只能使用interface {}类型,所以我将其省略了,因为它会使代码变得混乱。然而,如果我在后续的块中使用interface {}以及带有可选星号的返回属性(例如"NewMessageObject"),JSON构造函数似乎会忽略这些值,因为它们被包装在一个空接口中,而不是以原始类型暴露。然而,它们必须有一个nil选项...

问题出在哪里?总体设计有问题吗?我基本上是想以一种整洁的抽象方式根据输入数据构建一个JSON对象响应(或以JSON格式返回错误)。

英文:

I'm playing around with Go and having trouble adapting some of my "inheriting" designs from other languages to its structure. I've coded in OCaml and some other languages bearing a similar structure, but I'm confused. Without type inheritance it becomes a bit strange to return JSON from different places using shared structures.

I have to iterate recursively through input data as needed to build a single JSON object to respond with.

Take for instance:

{
    "appVersion": "1.0.0",
    "messageStatus": "received"
}

... and:

{
    "appVersion": "1.0.0",
    "uploadStatus": "received"
}

The only way I can find to make this work in Go so far is to copy and paste the base structure that includes "appVersion" into the two output generating functions separately, but I don't want to do that because I don't want to have to maintain the same set of code twice.

Here's where I'm stuck trying to fix that:

type JSONResponse struct {
    appVersion string
}
type MessageJSONResponse struct {
    JSONResponse
    messageStatus string
}
type UploadJSONResponse struct {
    JSONResponse
    uploadStatus string
}

... Then:

type Message struct {
	formattingVersion *int

}

func NewMessageObject(r *http.Request) (bool, *MessageJSONResponse) {
	message := new(Message)

	if (true) {
		// #TODO: INSERT LOGIC HERE!
		*message.formattingVersion = 2;

	}

	if (message.formattingVersion != nil) {
		response := new(MessageJSONResponse)
		response.messageStatus = "OK"

		return false, errorResponse

	}

	return true, nil

}

... And:

func init() {
	http.Handle("/endpoints/message", JSONResponseHandler(messageHandler))

}

func JSONResponseHandler(h func (w http.ResponseWriter, r *http.Request) interface {}) http.Handler {

// #TODO - convert `JSONResponse` into actual JSON or output JSON Error!

}

func messageHandler(w http.ResponseWriter, r *http.Request) JSONResponse { // #BROKEN TYPES?

	hasError, messageResponse := NewMessageObject(r)
	if (hasError || messageResponse==nil) { return nil } // #TODO
	////

	// #TODO ... more message things.

	return messageResponse;

};

This approach (sorry for any code mistakes, really long day and I'm headed to bed) doesn't work because in order to pass the varied return values around... the type can't change, etc.

The JSONResponseHandler wrapper method actually works on my end but only with the interface {} type given the variations in type... so I've left it out since it'd clutter up the code. However, if I use interface {} on subsequent blocks with optional asterisked return properties (such as "NewMessageObject"), the JSON constructors seems to ignore those values since they're wrapped in an empty interface instead of just exposed as their raw type. However, they have to have a nil option....

What's wrong? The design in general? I'm basically trying to build a JSON object response (or return with a JSON-formatted error) through subsequent calls based on input data... in a neatly abstracted way.

答案1

得分: 1

要解决你的JSON问题,你可以使用一个结构体,并使用json标签为每个字段标记:"omitempty":

package main

import (
    "encoding/json"
    "fmt"
)

type foostruct struct {
    Myfoo   string `json:"myfoo,omitempty"`
    Yourfoo string `json:"yourfoo,omitempty"`
    Ourfoo  string `json:"ourfoo,omitempty"`
}

func main() {
    j := []byte(`{"myfoo":"mine", "yourfoo":"yours"}`)
    fstruct := &foostruct{}
    err := json.Unmarshal(j, fstruct)
    if err != nil {
        panic(err)
    }

    b, err := json.Marshal(fstruct)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(b))
}

你会发现输出不包含字段"ourfoo":

{"myfoo":"mine","yourfoo":"yours"}

你可以在这里尝试运行代码:
http://play.golang.org/p/zKwFaxbLJu

英文:

To solve your json issue, you could use one struct and tag each field with json:"omitempty":

package main

import (
    "encoding/json"
    "fmt"
)

type foostruct struct {
    Myfoo   string `json:"myfoo,omitempty"`
    Yourfoo string `json:"yourfoo,omitempty"`
    Ourfoo string `json:"ourfoo,omitempty"`
}

func main() {
    j := []byte("{\"myfoo\":\"mine\", \"yourfoo\":\"yours\"}")
    fstruct := &foostruct{}
    err := json.Unmarshal(j, fstruct)
    if err != nil {
	    panic(err)
    }

    b, err := json.Marshal(fstruct)
    if err != nil {
	    panic(err)
    }

    fmt.Println(string(b))
}

You'll see the the output does not contain the field "ourfoo":

{"myfoo":"mine","yourfoo":"yours"}

Try it out here:
http://play.golang.org/p/zKwFaxbLJu

答案2

得分: 0

我在我的应用程序中使用map而不是struct,特别是当我想要返回一个JSON响应给客户端时。这样可以给我更多的灵活性。请看一下这个例子:

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	m := make(map[string]interface{})
	m["appVersion"] = "0.0.1"
	m["uploadStatus"] = "success"

	strJson, _ := json.Marshal(m)
	str := string(strJson)
	fmt.Println("---ENCODING--")
	fmt.Println(str)

	//put it back
	fmt.Println("---DECODING--")
	n := make(map[string]interface{})
	json.Unmarshal([]byte(str), &n)
	for key, val := range n {
		fmt.Println(key, ":", val)
	}
}

输出结果为:

---ENCODING--
{"appVersion":"0.0.1","uploadStatus":"success"}
---DECODING--
appVersion : 0.0.1
uploadStatus : success

你可以在这里查看:http://play.golang.org/p/h4b4-nkZ4M

英文:

I use map instead of struct on my application, especially when I want to return back a json answer to client. Its give me more flexibility. Please take a look this :

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	m := make(map[string]interface{})
	m["appVersion"] = "0.0.1"
	m["uploadStatus"] = "success"

	strJson, _ := json.Marshal(m)
	str := string(strJson)
	fmt.Println("---ENCODING--")
	fmt.Println(str)

	//put it back
	fmt.Println("---DECODING--")
	n := make(map[string]interface{})
	json.Unmarshal([]byte(str), &n)
	for key, val := range n {
		fmt.Println(key, ":", val)
	}
}

and the output is :

---ENCODING--
{"appVersion":"0.0.1","uploadStatus":"success"}
---DECODING--
appVersion : 0.0.1
uploadStatus : success

You can check here : http://play.golang.org/p/h4b4-nkZ4M

huangapple
  • 本文由 发表于 2016年4月12日 00:03:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/36553742.html
匿名

发表评论

匿名网友

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

确定