How to omit some parameters of structure Gin gonic - go

I have big structure with more than 50 params
type Application struct {
Id int64 `json:"id"`
FullName string `json:"fullName,omitempty"`
ActualAddress string `json:"actualAddress,omitempty"`
.....
}
I use gin-gonic and when I return application I need to omit some params I've created a function which makes empty some params (playLink) and then gin returns me correct json (without unnecessary values). I heard that reflection isn't fast operation so in our case we can use a lot of ugly if-else or switch-cases. Is there any other solutions faster than reflecting and more beautiful than if-elses?
The thing is that structure params have non-empty values, so they wont by omitted by gin. That's why I've created function to make some params empty before return

The thing is, if you only want to zero a few fields, it's more readable to do it without a function, e.g.
app := Application{}
app.FullName, app.ActualAddress = "", ""
If you want to create a function for it, at least use variadic parameter, so it's easier to call it:
func zeroFields(application *Application, fields ...string) {
// ...
}
So then calling it:
zeroFields(&app, "FullName", "ActualAddress")
Yes, this will have to use reflection, so it's slower than it could be, and error prone (mistyped names can only be detected at runtime). If you want to avoid using reflection, pass the address of the fields:
func zeroFields(ps ...*string) {
for _, p := range ps {
*p = ""
}
}
This way you have compile-time guarantee that you type field names correctly, and that they have string type.
Calling it:
zeroFields(&application.FullName, &application.ActualAddress)
Try it on the Go Playground.

If I understand correctly: you want to return some values from your struct but not all of them? Perhaps a nested struct?
type Application struct {
ID struct {
ID int64 `json:"id"`
} `json:"id"`
Person struct {
Fullname string `json:"Fullname"
} `json:"person"
}
That should let you filter out the fields you want to use.

Related

How to get all fields in a response in graphql without passing any field names in a query

I'm building a graphql interface using golang. I'm using gqlgen package to implement it.
Here I need to pass all field names in a query to get it in response, But the problem is my data is huge, it is having more than 30 fields it would be difficult to pass all fields in a query.
This is my query
{Model{id, name, email, mobile,...............}}
Like this I need to pass all fields name.
Instead Im looking for a result which will return all fields without passing any fields. I mean if not passing any field names it should return all.
For example
{Model{}}
First, you really should list out all the fields in your query. That is the nature of graphql. It is verbose, but most client libraries get the fields from your data structure anyway, so it's not that bad.
So I recommend listing out all fields manually!
Using Scalars (must be on v0.11.3 or below, see https://github.com/99designs/gqlgen/issues/1293)
But if you insist, if there is a will, there is way. You can use GraphQL's scalar types and make your own. See this doc for how to make them with gqlgen: https://gqlgen.com/reference/scalars/
In your schema, you can make a JSON scalar:
scalar JSON
type Query {
random: JSON!
}
Make a model for this
// in your own models.go
// You can really play with this to make it better, easier to use
type JSONScalar json.RawMessage
// UnmarshalGQL implements the graphql.Unmarshaler interface
func (y *JSONScalar) UnmarshalGQL(v interface{}) error {
data, ok := v.(string)
if !ok {
return fmt.Errorf("Scalar must be a string")
}
*y = []byte(data)
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (y JSONScalar) MarshalGQL(w io.Writer) {
_, _ = w.Write(y)
}
Then link the scalar to your custom type in the gql.yml
models:
JSON:
model: github.com/your-project/path/graph/model.JSONScalar
When you run the generate (use gqlgen v0.11.3 or below, gqlgen version), your resolvers will now use the custom type you made. And it's easy to use:
func (r *queryResolver) random(ctx context.Context) (model.JSONScalar, error) {
// something is the data structure you want to return as json
something := struct {
Value string
}{
Value: "Hello World",
}
d, _ := json.Marshal(something)
return model1.JSONScalar(d), nil
}
The resulting query of
// Query
{
random
}
// Response
{
"random" : {
"Value": "Hello World!"
}
}

Better way of decoding json values

Assume a JSON object with the general format
"accounts": [
{
"id": "<ACCOUNT>",
"tags": []
}
]
}
I can create a struct with corresponding json tags to decode it like so
type AccountProperties struct {
ID AccountID `json:"id"`
MT4AccountID int `json:"mt4AccountID,omitempty"`
Tags []string `json:"tags"`
}
type Accounts struct {
Accounts []AccountProperties `json:"accounts"`
}
But the last struct with just one element seems incorrect to me. Is there a way I could simply say type Accounts []AccountProperties `json:"accounts"` instead of creating an entire new struct just to decode this object?
You need somewhere to store the json string accounts. Using a:
var m map[string][]AccountProperties
suffices, though of course you then need to know to use the string literal accounts to access the (single) map entry thus created:
type AccountProperties struct {
ID string `json:"id"`
MT4AccountID int `json:"mt4AccountID,omitempty"`
Tags []string `json:"tags"`
}
func main() {
var m map[string][]AccountProperties
err := json.Unmarshal([]byte(data), &m)
fmt.Println(err, m["accounts"])
}
See complete Go Playground example (I had to change the type of ID to string and fix the missing { in the json).
As Dave C points out in comments, this is no shorter than just using an anonymous struct type:
var a struct{ Accounts []AccountProperties }
in terms of the Unmarshall call (and when done this way it's more convenient to use). Should you want to use an anonymous struct like this in a json.Marshall call, you'll need to tag its single element to get a lowercase encoding: without a tag it will be called "Accounts" rather than "accounts".
(I don't claim the map method to be better, just an alternative.)

Conditional (Dynamic) Struct Tags

I'm trying to parse some xml documents in Go. I need to define a few structs for this purpose, and my struct tags depend on a certain condition.
Imagine the following code (even though I know it won't work)
if someCondition {
type MyType struct {
// some common fields
Date []string `xml:"value"`
}
} else {
type MyType struct {
// some common fields
Date []string `xml:"anotherValue"`
}
}
var t MyType
// do the unmarshalling ...
The problem is that these two structs have lots of fields in common. The only difference is in one of the fields and I want to prevent duplication. How can I solve this problem?
You use different types to unmarshal. Basically, you write the unmarshaling code twice and either run the first version or the second. There is no dynamic solution to this.
The simplest is probably to handle all possible fields and do some post-processing.
For example:
type MyType struct {
DateField1 []string `xml:"value"`
DateField2 []string `xml:"anotherValue"`
}
// After parsing, you have two options:
// Option 1: re-assign one field onto another:
if !someCondition {
parsed.DateField1 = parsed.DateField2
parsed.DateField2 = nil
}
// Option 2: use the above as an intermediate struct, the final being:
type MyFinalType struct {
Date []string `xml:"value"`
}
if someCondition {
final.Date = parsed.DateField1
} else {
final.Date = parsed.DateField2
}
Note: if the messages are sufficiently different, you probably want completely different types for parsing. The post-processing can generate the final struct from either.
As already indicated, you must duplicate the field. The question is where the duplication should exist.
If it's just a single field of many, one option is to use embedding, and field shadowing:
type MyType struct {
Date []string `xml:"value"`
// many other fields
}
Then when Date uses the other field name:
type MyOtherType struct {
MyType // Embed the original type for all other fields
Date []string `xml:"anotherValue"`
}
Then after unmarshaling of MyOtherType, it's easy to move the Date value into the original struct:
type data MyOtherType
err := json.Unmarshal(..., &data)
data.MyType.Date = data.Date
return data.MyType // will of MyType, and fully populated
Note that this only works for unmarshaling. If you need to also marshal this data, a similar trick can be used, but the mechanics around it must be essentially reversed.

Subtypes Supertypes in go

Coming from OOP paradigms and porting a code from an OOP language, I come across a problem now which is solved in OOP via abstraction so I'm wondering how can I approach the following problem in Go which follows composition instead of inheritance.
In this scenario my ValueObjects (DTO, POJO etc.) are composed of other ValueObjects. I'm populating them through web service calls that returns json so basically my functions/method calls are common for all types and subtypes.
My super type EntityVO
type EntityVO struct {
EntityName string
EntityType string
PublicationId string
Version string
}
A subtype 1 composed with EntityVO
type ArticleVO struct {
EntityVO
ContentSize string
Created string
}
subtype 2 composed with EntityVO with it's own unique set of fields
type CollectionVO struct {
EntityVO
ProductId string
Position string
}
I'm calling web services to retrieve data and populate these VOs.
Earlier I had one function to call the web service and populate the data but now I'm duplicating the code for each VO.
type Article struct{}
func (a *Article) RequestList(articleVO *valueObject.ArticleVO) (*valueObject.ArticleVO, error) {
// some code
}
Duplicating the same code but changing the signature.
type Collection struct{}
func (c * Collection) RequestList(collectionVO *valueObject.CollectionVO) (*valueObject.ArticleVO, error) {
// some code - duplicate same as above except method signature
}
and I've several entities and just because my VO's are different I'm forced to duplicate the code and cater to each type of VO I've. In OOP sub types can be passed to a function accepting super types but not in go, so wondering how it should be done so I don't end up duplicated code that's different in signature only?
Any advice for a better approach in this kind of scenario?
This is where golang interfaces can shine.
It's worth noting, however, that it's difficult to write subclass/inheritance code in golang. We'd prefer thinking of it as composition.
type EntityVO interface {
GetName() string
SetName(string) error
GetType() string
...
}
type EntityVOImpl struct {
EntityName string
EntityType string
PublicationId string
Version string
}
func (e EntityVOImpl) GetName() string {
return e.EntityName
}
...
type ArticleVOImpl struct {
EntityVOImpl
ContentSize string
Created string
}
type CollectionVOImpl struct {
EntityVO
ProductId string
Position string
}
// CODE
func (e *Entity) RequestList(entityVO valueObject.EntityVO) (valueObject.EntityVO, error) {
// some code
}
In addition, as long as your interface files are shared, I don't think there should by any problem sending/marshalling/unmarshalling the structs over the wire.
The second parameter of json.Unmarshal is a "universal" interface{} type. I think similar approach is applicable to your case.
Define data type for storing web service properties which may differ for each entity, e.g.
type ServiceDescriptor struct {
URI string
//other field/properties...
}
Function for populating the entity may look like
func RequestList(desc *ServiceDescriptor, v interface{}) error {
//Retrieve json data from web service
//some code
return json.Unmarshal(data, v)
}
You can call the function to populate different type of entities, e.g.
desc := &ServiceDescriptor{}
article := ArticleVO{}
desc.URI = "article.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &article)
collection := CollectionVO{}
desc.URI = "collection.uri"
//...
//You must pass pointer to entity for 2nd param
RequestList(desc, &collection)

GO Multiple Pointers

I'm trying to create a function that receives multiple types of struct and add those pointer values to another function.
Example:
type Model1 struct {
Name string
}
type Model2 struct {
Type bool
}
func MyFunc(value ...interface{}) {
OtherFunc(value...)
}
func main() {
MyFunc( new(Model), new(Mode2) );
}
The problem is that OtherFunc only allow &value, &value, etc as parameter. Have some way to pass those values like OtherFunc(&value...)?
I'm not sure this will solve your problem entirely however, the exact thing you requested is a feature in the language. You just have to use composite-literal syntax for instantiation instead of new. So you could do this to pass pointers; MyFunc( &Model{}, &Mode2{} )
Thing is, you're still going to be dealing with an interface{} within MyFunc so I'm not sure that will just be able to call OtherFunc without some unboxing (would probably be a type assertion if you want to get technical).

Resources