Reputation: 5053
currently am working on an API Rest in Golang. I have the process to CRUD all the tables. Now someone is asking me to develop an endpoint to search in one of that tables based on the parameters send in the URL. Let's say that this is my struct for that table:
type Media struct {
ID uint
Key string
RecordKey string
RecordID string
SystemMediaKey string
MediaObjectID string
ChangedByID string
ChangedByKey string
MediaCategory string
MimeType string
ShortDescription string
LongDescription string
EntryTimestamp time.Time
ModificationTimestamp time.Time
DeletedAtTimestamp *time.Time
MediaModificationTimestamp time.Time
MediaURL string
MediaHTML string
Order int
Group string
Width int
Height int
ImageSize string
ResourceName string
ClassName string
Permission *string
MediaStatus string
}
Now, he can send me all or some of that fields in the URL, the I need to assign that values to my struct to be able to search in the database based on the data assigned to the object.
I am using Gorm to handle everything with the database, gorilla/schema to assign the values on the POST requests and the Julien Schmidt Router. Now,my questions are:
Upvotes: 1
Views: 3003
Reputation: 5053
I finally managed to use this library that converts a map to a struct. The only thing, is that I had to pre-process the map that is returned by URL.Query() Values
because it returns an array for each value and I needed only the value and not inside an array.
Upvotes: 0
Reputation: 6274
You could use the reflect
package to iterate over the fields and set them by name. Be aware that the reflect
package is arduous to use and comes with some dangers of panic
s if not used properly.
Also be aware that url.Values.Get
only returns the first value (see https://godoc.org/net/url#Values.Get for details)
EDIT: I added code to account for the pointers in the struct. They are handled differently.
https://play.golang.org/p/AO4lYx7xka
package main
import (
"fmt"
"net/url"
"reflect"
"time"
)
type Media struct {
ID uint
Key string
RecordKey string
RecordID string
SystemMediaKey string
MediaObjectID string
ChangedByID string
ChangedByKey string
MediaCategory string
MimeType string
ShortDescription string
LongDescription string
EntryTimestamp time.Time
ModificationTimestamp time.Time
DeletedAtTimestamp *time.Time
MediaModificationTimestamp time.Time
MediaURL string
MediaHTML string
Order int
Group string
Width int
Height int
ImageSize string
ResourceName string
ClassName string
Permission *string
MediaStatus string
}
func main() {
testUrl := "www.example.com/test?MimeType=themimetype&Key=thekey&Permission=admin"
u, err := url.Parse(testUrl)
if err != nil {
fmt.Println(err)
return
}
params := u.Query()
media := &Media{}
val := reflect.ValueOf(media)
for i := 0; i < val.Elem().NumField(); i++ {
// get the reflect.StructField so we can get the Name
f := val.Elem().Type().Field(i)
// check if URL.Values contains the field
if v := params.Get(f.Name); v != "" {
// get the reflect.Value associated with the Field
field := val.Elem().FieldByName(f.Name)
kind := field.Kind()
// you must switch for each reflect.Kind (associated with the type in your struct)
// so you know which Set... method to call
switch kind {
case reflect.String:
field.SetString(v)
case reflect.Ptr:
// pointers are a special case that must be handled manually unfortunately.
// because they default to nil, calling Elem() won't reveal the underlying type
// so you must simply string match the struct values that are pointers.
switch f.Name {
case "Permission":
newVal := reflect.New(reflect.TypeOf(v))
newVal.Elem().SetString(v)
field.Set(newVal.Elem().Addr())
case "DeletedAtTimestamp":
}
}
}
}
fmt.Printf("%#v\n", media)
fmt.Println(*media.Permission)
}
Upvotes: 1