简体   繁体   中英

Golang: Json from URL as map

What is the best way to extract json from a url ie Rest service from Go? Also it seems most rest client libraries in go force a use of the json.marshall which needs a struct to be used with it.

This doesn't work in the case of unstructured data where you don't fully know what will be coming in. Is there a way to have it all simply come in as a map[string:string]?

Why not to parse it into map[string]string as this code have to do

var d map[string]interface{}
data, err := json.Unmarshal(apiResponse, &d)

You can traverse data in this struct too.

If you suspect, that api response can be not singular object, but the collection of objects, the interface{} also works for arrays.

If you don't know what's coming in a message, you can have several situations.

Message contents that depend on type

Type is usually indicated by some type field. In this case you can use a "union" struct that contains fields from all types:

type Foo struct {
    A int
    B string
}

type Bar struct {
    C int
    D string
}

type Message struct {
    Type string
    Foo
    Bar
}

// or this, if you have common fields

type Message struct {
    Type string
    A int
    B string
    C int
    D string
}

Unmarshal the message into the union struct, dispatch on type, and select the sub-struct.

var m Message
json.Unmarshal(data, &m)
switch m.Type {
    case "foo":
        ...
    case "bar":
        ...
}

Completely dynamic messages

In this case you have a collection of unrelated key-values and process them individually.

Parse into a map[string]interface{} . The downside, of course, is that you have to cast each value and check its type dynamically. Caveat: map[string]interface{} will convert all numbers to floats, even integers, so you have cast them to float64 .

You can also use map[string]json.RawMessage , if you do not want to parse values, only keys ( json.RawMessage is a []byte , and is preserved as is when unmarshaled).

"Envelope" message with dynamic payload

For example:

{
    "type": "foo",
    "payload": {
        "key1": "value1"
    }
}

{
    "type": "bar",
    "payload": {
        "key2": "value2",
        "key3": [1, 2]
    }
}

Use a struct with json.RawMessage .

type Message struct {
    Type string
    Payload json.RawMessage
}

type Foo struct {
    Key1 string
}

type Bar struct {
    Key2 string
    Key3 []int
}

Parse the envelope (payload will be preserved), then dispatch on type, and parse payload into a sub-struct.

var m Message
_ = json.Unmarshal(data, &m)
switch m.Type {
    case "foo":
        var payload Foo
        _ = json.Unmarshal(m.Payload, &payload)
        // do stuff
    case "bar":
        var payload Bar
        _ = json.Unmarshal(m.Payload, &payload)
        // do stuff
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM