Is there a way to have a dynamic type slice in Go? - go

I have a standard response built in PHP for microservices that I want to replicate in Go.
In particular, the "data" element of the response array can have anything.
Example
$response['data'] = [];
$response['data']['entities'] = [ objects that implements toArray() ]
$response['data']['quantity'] = 1
Problem is that Data differs per endpoint.
So one option I was thinking is in each endpoint (controller, action, etc) declare a Data struct that I would use in the StandardResponse.Data struct.
But how can I achieve that? Using interfaces?
Sorry I am new to Go.

An interface{} is one way to do it. Something like:
type StandardResponse struct {
Error bool
ErrorMsg string
Data interface{}
}
Marshaling this to JSON will work assuming the underlying type of interface{} supports it.

Related

How to process pair array data

I have json data like:
`[{"fea1":12345},{"fea2":23456}]`
I want to unmarshal them into Go structs.
Now I defined a struct like []map[string]int.
It works, but I think this is not the best way which processing pair data with map structure.
Processing large data set also cost much resource if using map structure.
Is there a more graceful way to implement it?
If you have predefined set of fields, you may use struct like this:
type Fea struct {
Fea1 int `json:"fea1,omitempty"`
Fea2 int `json:"fea2,omitempty"`
}
type Feas []Fea
var feas Feas
Then Unmarshal to feas. This way present fields would be filled, others would be empty.

Polymorphism on structs without methods in Go

I'm working on several web server projects in Go, and there is a common problem that I'm always facing. I know we can achieve something like polymorphism in Go with interfaces and methods, but many times I had a scenario that I needed polymorphism on some data-holder structs that (maybe) just had some common fields, and no methods at all.
For example consider a story writing platform, where each user can write short stories and novels:
type ShortStory struct {
Name string
ID int
Body string
}
type LongStory struct {
Name string
ID int
Chapters []string
}
Now I simply want to have a data layer function, say GetStories(), which fetches all stories written by a user from database.
func GetStories(id int) []SOME_TYPE {
...
}
There are really no methods that I want to have on my ShortStory and LongStory structs. I know I can add a dummy method and let them satisfy some Storier interface, then use that interface as return type. But since there is no method I would want on a data container model, adding a dummy method just for the language to enable a feature, seems like a poor design choice to me.
I can also make the function return []interface{}, but that's against the whole idea of "typed language" I believe.
Another way is to have two separate GetShortStories() and GetLongStories() methods, which return a slice of their own type. But at some point I would finally want to merge those two slices into one and there I would again need a []interface{}. Yes, I can return a JSON like:
{
"short_stories" : [...],
"long_stories" : [...]
}
But I want my json to be like:
[{...}, {...}, {...}]
And I wouldn't change my APIs because of a language's limits!
I'm not a pro in Go, so am I missing something here? Is there a Go-ish approach to this, or is it really bad language design on Golang's side?
If you cannot express what you want to do using the features of a language, you should first try to change the way you structure your program before blaming the language itself. There are concepts that cannot be expressed in Go but can be expressed well in other languages, and there are concepts you cannot express well in other languages but you can in Go. Change the way you solve the problem to effectively use the language.
One way you can address your problem is using a different type of struct:
type Story struct {
Name string
ID int
ShortBody string
Chapters []string
}
If the Chapters is empty, then it is a short story.
Another way:
type Story struct {
Name string
ID int
Content StoryContent
}
type StoryContent interface {
Type() string
}
type ShortStory interface {
StoryContent
Body() string
}
type LongStory interface {
StoryContent
Chapters() []string
}
etc.

Convert interface{} to struct in Golang

I am very new to Go and am trying to get my head around all the different types and how to use them. I have an interface with the following (which was originally in a json file):
[map[item:electricity transform:{fuelType}] map[transform:{fuelType} item:gas]]
and I have the following struct
type urlTransform struct {
item string
transform string
}
I have no idea how to get the interface data into the struct; I'm sure this is really stupid, but I have been trying all day. Any help would be greatly appreciated.
Decode the JSON directly to types you want instead of decoding to an interface{}.
Declare types that match the structure of your JSON data. Use structs for JSON objects and slices for JSON arrays:
type transform struct {
// not enough information in question to fill this in.
}
type urlTransform struct {
Item string
Transform transform
}
var transforms []urlTransform
The field names must be exported (start with uppercase letter).
Unmarshal the JSON to the declared value:
err := json.Unmarshal(data, &transforms)
or
err := json.NewDecoder(reader).Decode(&transforms)
From your response : [map[item:electricity transform:{fuelType}] map[transform:{fuelType} item:gas]].
As you can see here this is a an array that has map in it.
One way to get the value from this is :
values := yourResponse[0].(map[string]interface{}). // convert first index to map that has interface value.
transform := urlTransform{}
transform.Item = values["item"].(string) // convert the item value to string
transform.Transform = values["transform"].(string)
//and so on...
as you can see from the code above I'm getting the the value using map. And convert the value to the appropriate type in this case is string.
You can convert it to appropriate type like int or bool or other type. but this approach is painful as you need to get the value one bye one and assign it your your field struct.

Conversion of Go struct fields with tags

I am really stuck here with a seemingly trivial problem in Go:
I have a Golang microservice, which outputs data in json format. Let's say I have a simple struct with json tags for this result:
type Result struct {
Name string `json:"name"`
Age int `json:"age"`
}
In the code part where the data is actually pulled out of the database, I have a quite similar struct, like this:
type ResultBackend struct {
Name string `bson:"fullName"`
Age int `bson:"age"`
}
The struct fields are similar, except the different tags. I would like to keep things simple, and return just one struct from the backend service (ResultBackend), which can then be send as a JSON response, like this:
func process() Result {
var result ResultBackend
... do a MongoDB query here and store results in result variable ...
return result
}
This certainly would not work, because we have two different structs here.
Of course one solution would be to embed both tags in one struct like so:
type Result struct {
Name string `json:"name" bson:"fullName"`
Age int `json:"age bson:"age"`
}
and then use this struct in the main code and the "process" function.
This works, but this seems like "poisoning" the Result struct of the main code with the bson tags. What, for instance, if the backend result is a XML file? I'd have to add xml tags to the struct as well. Or maybe someday tags some very obsure database adapter.
This doesn't seem to be the cleanest approach in my eyes. I'd rather have a clean Result struct in the main code, and simply to a conversion from one struct to another.
Is there any easy way doing that, or do I really have to copy all the fields of a ResultBackend struct to a new Result struct and return that? Or I am trying to over-simplify my code here? :)
Cheers!
What I'd do is create a separate type for every "serialisation format" if you will. This approach has several advantages:
Your concerns are separated.
JSON un/marshalling doesn't interfere with BSON/XML, so you can add any kind of additional struct fields (like xml.Name for example).
You can actually create several such types for different APIs that need different parameters.
The only disadvantage I see is that it's more code and even more code to move data between those. Ultimately it's up to you and your application design. If you're sure that your JSON/BSON will stay the same, you can use one type. Otherwise, I'd recommend specialisation.
To those who want to add bson tags in golang struct, here is a tool which can be helpful. I have spent a whole day searching for this and I want others to save their valuable time.
You can convert the following struct
type Result struct {
Name string `json:"name"`
Age int `json:"age"`
}
into
type Result struct {
Name string `json:"name" bson:"fullName"`
Age int `json:"age bson:"age"`
}
With this tool, you can not only add bson tags but also
XML tags,
Define validation and scope
Format tag values
Apply transformation
skip unexported fields.
Go Modify Tags: https://github.com/fatih/gomodifytags
Cheers,

Marshalling pointers using mgo.Marshal()

I want to encode pointers differently than from values. Currently, if we have a struct:
type Order struct {
Item Tool
AssociatedItem *Tool
}
both get inlined into a Order document inside mongo when marshalling.
I need to be able to perform my own serialization in the case of a *Tool. For instance, I could in this case only store the Id for the Too instead of the whole content. Unfortunately the overriding mechanism in mgo is to define a SetBSON() GetBSON for the Tool but it doesn't differentiate between pointers and non pointers.
What would be the best way to handle this?
Use a different type for "pointers", for example:
type SelectiveTool Tool
func (st *SelectiveTool) SetBSON(raw bson.Raw) error {
return raw.Unmarshal(s)
}
type Order struct {
Item Tool
AssociatedItem *SelectiveTool
}

Resources