donglikuang8145 2019-08-29 16:27
浏览 60
已采纳

如何在Go中构建抽象的json解组器

I have multiple APIs that follow a similar structure on the high level response. It always gives back an answer in that form:

{"data": {"feed":[{...}]}, "success": true}

However, the structure in Feed varies, depending on the concrete API.

I would now like to build an abstract function to process the various APIs. I have the following objects:

type SourceDTO struct { // top level object
    Success bool       `json:"success"`
    Data    Feed       `json:"data"`
}

type Feed struct {
    FeedData []<???> `json:"Feed"`
}

(The real object is more complex, but this shows the idea)

How would be a good way in go to parse this for the different APIs, ut having some common code with some logic based on the high level data (e.g. success)?

EDIT: I am extending this, to explain more the extend of my question about the "pattern" I am looking for.

I want to create this package that parses the group of APIs. The DTO objects then have to be transferred into some other objects. These 'final' objects are defined in a different package (the entity package) and have then to be persisted.
I am now wondering, how to bring all this together: The 'finaly' entity objects, the transformation functions from DTO to entity, the parsing of the different APIs and their common and different result components.
Where do the transformation functions belong to (package wise)?

EDIT2: Specified FeedData to a slice after digging into the problem (see comments)

  • 写回答

2条回答 默认 最新

  • douyinghuo8874 2019-09-03 16:25
    关注

    Thanks to @mkopriva for the input for this solution.

    In order to have some abstraction in your json unmarshalling it is possible to use interface{} for many use cases.

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type UniversalDTO struct {
        Success bool        `json:"success"`
        Data    interface{} `json:"data"`
    }
    
    type ConcreteData struct {
        Source string `json:"source"`
        Site   string `json:"site"`
    }
    
    func main() {
        jsondata := []byte(`{"sucess":"true","data":[{"source":"foo","site":"bar"}]}`)
    
        data := make([]ConcreteData, 0, 10)
        dtoToSend := UniversalDTO{Data: &data}
    
        describe(dtoToSend)
        describe(dtoToSend.Data)
    
        json.Unmarshal(jsondata, &dtoToSend)
    
        describe(dtoToSend)
        describe(dtoToSend.Data)
    }
    
    func describe(i interface{}) {
        fmt.Printf("(%v, %T)
    ", i, i)
    }
    

    Test here: https://play.golang.org/p/SSSp_zptMVN

    json.Unmarshal expects an object into which the json is being put into. Thus, first we always need an object. Depending on the concrete instance of the target object, the interface{} can be overriden with a concrete struct object (which of course has to be created separately). An important learning here is, that a go interface can also be overridden with a slice. In this way, it is also possible to unmarshal an array into a go object. However, a slice of a struct has to be defined as a slice of pointers to that type.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 Qt下使用tcp获取数据的详细操作
  • ¥15 idea右下角设置编码是灰色的
  • ¥15 全志H618ROM新增分区
  • ¥15 在grasshopper里DrawViewportWires更改预览后,禁用电池仍然显示
  • ¥15 NAO机器人的录音程序保存问题
  • ¥15 C#读写EXCEL文件,不同编译
  • ¥15 MapReduce结果输出到HBase,一直连接不上MySQL
  • ¥15 扩散模型sd.webui使用时报错“Nonetype”
  • ¥15 stm32流水灯+呼吸灯+外部中断按键
  • ¥15 将二维数组,按照假设的规定,如0/1/0 == "4",把对应列位置写成一个字符并打印输出该字符