I'm a little new to golang and trying to process some websocket data.
I get data in the form of:
type Event struct {
Event string `json:"event"`
Data interface{} `json:"data"`
}
And the Data
field is a json object that I want to process and get into the following struct:
type OrderBook struct {
Pair string `json:"pair"`
Timestamp string `json:"timestamp"`
Broker string `json:"broker"`
Bids []OrderBookItem `json:"bids"`
Asks []OrderBookItem `json:"asks"`
}
type OrderBookItem struct {
Price float64
Amount float64
}
from the websocket function:
....
case "data":
publish(e.Data) <--- this is where the error occurs
....
which calls:
func publish(data OrderBookResult) {
log.Println("Publishing trade data...", data)
o := &OrderBook{}
o.Pair = "BTCEUR"
o.Timestamp = data.Timestamp
o.Broker = "Bitstamp"
o.Asks = data.Asks
o.Bids = data.Bids
}
The error in the websocket function I get is the following:
cannot use e.Data (type interface {}) as type OrderBookResult in argument to publish: need type assertion
How can I "cast" the websocket struct into the new struct and reference fields, that are not defined on the websocket struct. I have a node.js
background and I haven't gotten my head around the strictness of go yet.
Thx
As others have noted type assertions would be the answer to solve your immediate error given the interface contains the right type of struct.
But if your interface comes from JSON parsing, it will likely contain a map[string]interface{}
and not a OrderBookResult
. See here for why that is the case.
To solve that please read up on how to create a custom JSON marshaller. For example in this blog. Below I have also included a way of processing a map[string]interface{}
to get to your data in the publish function.
So you can either type assert before you call:
....
case "data":
// Assert that e.Data is in fact a struct of type OrderBookResult
if dataAsOrderBookResult, ok := e.Data.(OrderBookResult); ok {
publish(dataAsOrderBookResult)
} else {
// handle error etc
...
}
....
Or change the signature of your publish function and type assert the parameter inside:
func publish(data interface{}) {
log.Println("Publishing trade data...", data)
o := &OrderBook{}
// Type switch
switch v := data.(type) {
case OrderBookResult:
o.Pair = "BTCEUR"
o.Timestamp = v.Timestamp
o.Broker = "Bitstamp"
o.Asks = v.Asks
o.Bids = v.Bids
case map[string]interface{}:
o.Pair = "BTCEUR"
o.Timestamp = v["Timestamp"].(string)
o.Broker = "Bitstamp"
// here again you need to type assert correctly and it may be a map again
//o.Asks = v["Asks"].(OrderBookItem)
//o.Bids = v["Bids"].(OrderBookItem)
default:
// error handling etc.
...
}
...
}