1

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:

  1. What should I configure in the route to accept dynamic parameters?
  2. How can I assign the values that comes in the URL to the a type Media object? Thank you!
4
  • Clarification. Are these GET parameters you are referring to? Commented Jul 3, 2017 at 21:03
  • @RayfenWindspear yes, that are all the fields that conform the struct. And from the client side they can send me some of them with values to make the filter Commented Jul 3, 2017 at 21:05
  • Then all you need is to map the URL.Query() Values to your struct? (godoc.org/net/url#URL.Query) Commented Jul 3, 2017 at 21:13
  • @RayfenWindspear correct! Commented Jul 3, 2017 at 21:16

2 Answers 2

1

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 panics 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) } 
Sign up to request clarification or add additional context in comments.

4 Comments

While I don't exactly advocate for using the reflect package unless necessary, I can't resist a fun challenge to use it. Using it sort of walks the lines of the "here be dragons" territory.
Another solution that would be easier to implement would be to json.Marshal the url.Values map, then json.Unmarshal it back into your struct. This method may actually be easier to implement, but the JSON encoder/decoder tends to be rather bulky and less efficient. It might be less than straightforward though because url.Values is a map[string][]string so it would Marshal the values as arrays. This is why I opted for directly using the reflect package, because I knew off the top of my head roughly how it would work (and that it would).
finally I managed to use this library that I found godoc.org/github.com/mitchellh/mapstructure#Decode it makes the job
Hmm look at that. You found a nice library that does the same thing. It's usually best to use a lib rather than reinvent the wheel. I suggest you post this as an answer to your own question. It's a good library, as far as I can tell at first glance.
0

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.

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.