1

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!

4
  • I certainly recommend copying all the fields into a new struct because that one won't have those pesky annotations. It will do your application well. Commented Aug 3, 2015 at 15:30
  • I'm being sarcastic of course. What's more important; the performance of your application or whether or not you have to read some text the compiler uses? Commented Aug 3, 2015 at 15:31
  • Without being sarcastic: Performance, yes. But also readability of my code and independence to (future) backend services. I prefer to touch as little code as possible whenever a backend service changes. And as I said, this only works of course for results which can be serialized with tags. If I use some esoteric backend which does not support tags (or json or XML or ...), I'd have to copy those fields into the struct anyway, right? Commented Aug 3, 2015 at 15:35
  • As a compromise I would recommend using an interface in your application layer and having different types implement it on the two ends of the data divide (client and db sides). That being said, if the model is the same on both sides why in the hell wouldn't you use the same object!? If your model changes to XML on the backend you just find and replace bson with xml, having different structs isn't gonna make that change any different. Also, adding superfluous types isn't going to make your program more readable, it's going to make future devs scorn you. Commented Aug 3, 2015 at 15:49

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, I guess that's the best of both worlds, I'' try that approach. Cheers!
0

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,

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.