Dynamic Nested structure in GoLang - go

I am learning golang and want to write generic response from microservices response.
My General Response is like:
type GeneralResponse struct {
Success string
Message string
Data string
Error string
}
In the Data section I want to return any json, say list of Person, Instruments or any type of objects.
But it should be another json.
I tried assigning other json objects but it did not work.
It is fine if I dump json array as string into it but it should unmarshal from receiver end.
How should I go about it?
I am trying over here. https://play.golang.org/p/dc0uKtS76aA

You should use RawMessage in the type definition
type GeneralResponse struct {
Success string
Message string
Data json.RawMessage
Error string
}
and subsequently push a Marshalled json into that attribute.
You can do that by encoding other types in []bytes and setting them to the Data attribute.
Like in https://play.golang.org/p/CyoN5pe_aNV

If you put marshalled JSON into a string, it will be marshalled as a string (because it's a string) and the receiving end will have to unmarshal it twice (because it's been marshalled twice). What you want is probably more along the lines of:
type GeneralResponse struct {
Success string
Message string
Data interface{} // interface{} can be anything
Error string
}
This way you can put any data into Data and it will be marshalled directly into the response.

You can use json.RawMessage for that.
I have implemented the encoding part, you find more here to decode - https://golang.org/pkg/encoding/json/#RawMessage

json.RawMessage comes to rescue in case you wants to capture whole json without knowing its format.
type GeneralResponse struct {
Success string
Message string
Data json.RawMessage
Error string
}
Checkout this code. I have modified your code to dump data into response

Related

Converting Go []interface{} to protobuf Repeated Array

I have a service written in Go that get data from rest api and return that data as a grpc server. I got an array of object. And I want to return it through the grpc protobuf file. But it keeps failing because of type issue as the data from the api is []interface{} and I don't know how to return this through protobuf response.
Below is the go lang code
        return &waas.BankListResponse{
                Status:  result.Data["Status"].(bool),
                Message: result.Data["Message"].(string),
                Data: result.Data["banks"].([]*waas.Banks),
        }, nil
The proto file
message banks {
  string bankCode = 1;
  string bankName = 2;
}
  message BankListResponse {
    bool Status =1;
    string Message = 2;
    repeated banks data = 3;
  }
So the result.Data["bank"] is the array of banks and the data type is []interface{}
sample data
{
"banks": [
{
"bankCode":"",
"bankName":""
},
{
"bankCode":"",
"bankName":""
}
]
}
So can someone assist me point out how return such data on the proto file.
you need to write custom code to transfer data from the interface to your proto object. you will return this new proto object as the response.

Go JSON Marshal, is there a better way?

I have a struct that is populated with Unmarshal from a web response. Then I want to take a particular nested field from this JSON structure and feed it into a different web request. The issue is that the field name gets removed when using Marshal. As a workaround, right now I'm doing the equivalent of:
type Message struct {
Dogs json.RawMessage `json:"doggies"`
}
...
type Doggies struct {
Dogs json.RawMessage `json:"doggies"`
}
var msg Message
// msg gets populated from a request
postBody, err := json.Marshal(Doggies{Dogs: msg.Doggies})
Which is messy. Is there a way that I can get Marshall to include the field name? So instead I could have
postBody, err := json.Marshal(msg.Doggies)
Thank you

Can gRPC method return a message with a field that could be string or null?

I'm designing a gRPC service written in Go.
In front of the gRPC service is Envoy which converts incoming HTTP requests to gRPC and converts the gRPC responses to JSON.
The requirement of this application is to have an endpoint that returns the following JSON object:
{
my_id: "AAA"
}
I can model this response pretty simply in Go like this:
// A MyResponse object.
message MyResponse {
// contents is a list of contents.
string my_id = 1;
}
But the requirement that I have is that sometimes my_id might be null. In that case, I want to get the following JSON back:
{
my_id: null
}
it
Is it possible to modify MyResponse such that my_id can be a string or a null in the JSON object that is returned? If so, how? If not, isn't this a pretty big gap in the design of gRPC?
I suggest you to use the StringValue field of the Package google.protobuf:
StringValue Wrapper message for string.
The JSON representation for StringValue is JSON string.
So in your proto files, you should import:
import "google/protobuf/wrappers.proto";
then use as example:
google.protobuf.StringValue name = 2;
For handle the values you can check the wrappers.StringValue
type of the github.com/golang/protobuf/ptypes/wrappers package and the helpers of the google.golang.org/protobuf/types/known/wrapperspb repo.

How to create type for interface in gRPC Protobuf?

We have common Auth service for all microservices.
When we validate request in response, we send JSON that look like this.
{
Auth: bool,
Body: interface{}
}
While writing proto3 syntax, how can we write something like an interface type?
I have tried using Any type, but I am not able to use it as we need to pass message type in type url which I am not able to generate.
Proto message for response
message AuthResponse {
bool Auth = 1;
google.protobuf.Any Body = 2;
}
Can anyone help here?
You can set the body type to bytes.
If you have a pre-defined set of types that your body could be, then I suggest you change your Auth struct to something like this:
type AuthResponse struct {
Auth bool
Body Encodable
}
// Encodable defines types that can be encoded into a byte slice.
type Encodable interface {
Encode() []byte
}
Then, implement Encode() []byte on each of your types.
Alternatively, if your Body field can be anything, then perhaps a similar solution, except your Encode function would look like this:
func Encode(interface{}) []byte
In this scenario, though, you may have to use some reflection magic in order to encode it to some byte slice. You could even use JSON.
I hope this helps!

How pass different structures to function?

I have several different structures.
Here show two:
type AdsResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
type OtherResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
but i don't know how i can do for this method accepts and return both.
func Get(url string, response Response) (Response, bool) {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(&response)
return response, true
}
And use like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", struct1)
Get("someURL", struct2)
There are any form?
Your code example is somewhat confusing since both structs appear to be identical. I'll assume that they differ somewhere in "others".
First, I generally recommend creating a wrapper around these kinds of JSON deserializations. Working directly on the JSON structure is fragile. Most of your program should not be aware of the fact that the data comes down in JSON. So for instance, you can wrap this in an Ads struct that contains an AdsResponse, or just copies the pieces it cares about out of it. Doing that will also make some of the below slightly easier to implement and less fragile.
The most common solution is probably to create an interface:
type Response interface {
ID() int
}
You make both Ads and Others conform to Response. Then you can return Response. If necessary, you can type-switch later to figure out which one you have and unload other data.
switch response := response.(type) {
case Ads:
...
case Other:
...
}
I don't quite get why you have the reponse as a parameter and as a return. I think you dont need to return it. You should pass a pointer to the reponse and fill it with the data. Also, I'd return an Error instead of a boolean, but that is another topic.
Anyway, the solution is to use interface{} (empty interface).
You are lucky because the function you are using (FromJsonTo) accepts an empty interface as a parameter, so you can safely change your parameter type to interface{} and just pass it to FromJsonTo. Like this:
func Get(url string, response interface{}) bool {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(response)
return true
}
Warning: I did not compile the code.
Then you would call this function with the url and a pointer to one of the reponse structs like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", &struct1)
Get("someURL", &struct2)
The way to achieve this is through Go's interfaces.
Two options:
empty interface
Get(url string, response interface{}) (Response, bool)
This option allows any value to be given to this function.
custom interface
Creating a custom interface will allow you to narrow down the types that can be provided as arguments to your function.
In this case you'll have to create an interface that all your Response structs will need to abide by. Any struct really that abides by that interface will be able to be used as an argument of your function.
Something like this:
type MyResponse interface {
SomeFunction()
}
Then your function signature could look like
Get(url string, response MyResponse) (MyResponse, bool)
As long as AdsResponse and OtherResponse abide by the MyResponse interface, they will be allowed to be used as arguments to the function.
Follow the solution working at Go Playground
Go has no polymorphic or any other OO like behaviour, so, when you try to pass a AdsResponse or OtherResponse struct as an Response (or any interface{}), these values becomes an Response (or other param type specified), and is not possible to Go to infer the real type that originate these interface{} and correctly decode your json to these struct types as expected.
This kind of thing should works perfectly in OO languages, like Java, C# etc. There is no hierarchy generalization/specialization on structs/interfaces in Go.
You would need to do a type assertion in your Rest executor, or a switch case, but it seems that you need a generic REST executor, like a generic lib some thing like that. Would not reasonable create a switch case for each struct in your program. Maybe you have dozens or hundreds of structs soon.
I think that a reasonable solution is the rest client pass a lambda function to do the last step for your, that is just create a correct struct destination type and call json decode.
As i say above, the return type of executeRest() in my example will became an interface{}, but the rest client can securely do the type assertion of returned value after executeRest() call.

Resources