duanmao1319 2013-06-22 16:34
浏览 37
已采纳

将复杂的JSON解析为goweb REST Create()函数

I apologise in advance for a very long question. Hopefully you'll bear with me.

I'm working with the goweb library, and experimenting with the example web app.

I've been trying to modify the RESTful example code, which defines a Thing as:

type Thing struct {
    Id   string
    Text string
}

A Thing is created by sending an HTTP Post request, with an appropriate JSON body, to http://localhost:9090/things. This is handled in the example code in the Create function, specifically the lines:

dataMap := data.(map[string]interface{})

thing := new(Thing)
thing.Id = dataMap["Id"].(string)
thing.Text = dataMap["Text"].(string)

This is all well and good, and I can run the example server (which listens on http://localhost:9090/) and the server operates as expected.

For example:

curl -X POST -H "Content-Type: application/json" -d '{"Id":"TestId","Text":"TestText"}' http://localhost:9090/things

returns with no error, and then I GET that Thing with

curl http://localhost:9090/things/TestId

and it returns

{"d":{"Id":"TestId","Text":"TestText"},"s":200}

So far, so good.

Now, I would like to modify the Thing type, and add a custom ThingText type, like so:

type ThingText struct {
    Title   string
    Body    string
}

type Thing struct {
    Id   string
    Text ThingText
}

This in itself isn't an issue, and I can modify the Create function like so:

thing := new(Thing)
thing.Id = dataMap["Id"].(string)
thing.Text.Title = dataMap["Title"].(string)
thing.Text.Body = dataMap["Body"].(string)

and the run the previous curl POST request with the JSON set to:

{"Id":"TestId","Title":"TestTitle","Title":"TestBody"}

and it returns with no error.

Once again I can GET the Thing URL and it returns:

{"d":{"Id":"TestId","Text":{"Title":"TestTitle","Body":"TestBody"}},"s":200}

Again, so far, so good.

Now, my question:

how do I modify the Create function to allow me to POST complex JSON to it?

For example, that last returned JSON string above includes {"Id":"TestId","Text":{"Title":"TestTitle","Body":"TestBody"}}. I'd like to be able to POST that exact JSON to the endpoint and have the Thing created.

I've followed the code back, and it seems that the data variable is of type Context.RequestData() from https://github.com/stretchr/goweb/context, and the internal Map seems to be of type Object.Map from https://github.com/stretchr/stew/, described as "a map[string]interface{} with additional helpful functionality." in particular, I noticed "Supports dot syntax to set deep values."

I can't work out how I can set up the thing.Text.Title = dataMap... statement so that the correct JSON field is parsed into it. I can't seem to use anything other than string types in the dataMap, and if I try that JSON it gives an error similar to:

 http: panic serving 127.0.0.1:59113: interface conversion: interface is nil, not string

Once again, sorry for the ridiculously long question. I really appreciate you reading, and any help you may have to offer. Thanks!

  • 写回答

1条回答 默认 最新

  • dongtan8979 2013-06-22 21:08
    关注

    As the JSON package documentation and JSON and Go introduction describe, JSON data can be parsed either generically through interface{} / string maps or unmarshalling directly to the struct types.

    The example code you linked to and you based your changes on seems to use the generic string-map approach, dataMap := data.(map[string]interface{}).

    As your desired JSON data is an object in an object, it’s simply a map within a map.

    So you should be able to

    dataMap := data.(map[string]interface{})
    subthingMap := dataMap["Text"].(map[string]interface{})
    thing.Text.Title = subthingMap["Title"].(string)
    thing.Text.Body = subthingMap["Body"].(string)
    

    I’m not sure why that code uses casts and generic types over type-safe unmarshalling directly from JSON to struct types (abstraction I guess). Using the json packages unmarshalling to struct types would go something like

    type ThingText struct {
        Title   string
        Body    string
    }
    
    type Thing struct {
        Id   string
        Text ThingText
    }
    
    …
    decoder := json.NewDecoder(body)
    var thingobj Thing
    for {
        if err := decoder.Decode(&thingobj); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Println(thingobj)
    }
    

    where body is a io.Reader - in simple/most cases from http.Response.Body.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程