英文:
Handle dynamic parameters in URL in Golang
问题
目前我正在使用Golang开发一个API Rest。我已经完成了对所有表进行CRUD操作的过程。现在有人要求我开发一个端点,根据URL中发送的参数在其中一个表中进行搜索。假设这是我用于该表的结构体:
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
}
现在,他可以在URL中发送所有或部分字段,然后我需要将这些值分配给我的结构体,以便能够根据分配给对象的数据在数据库中进行搜索。
我正在使用Gorm处理与数据库的所有操作,使用gorilla/schema将值分配给POST请求,并使用Julien Schmidt Router。现在,我的问题是:
- 在路由中应该配置什么来接受动态参数?
- 如何将URL中的值分配给Media对象的属性?
谢谢!
英文:
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:
- What should I configure in the route to accept dynamic parameters?
- How can I assign the values that comes in the URL to the a type Media object?
Thank you!
答案1
得分: 1
你可以使用reflect
包按名称迭代字段并设置它们。请注意,reflect
包使用起来比较麻烦,并且如果使用不当可能会导致panic
的危险。
另外,请注意url.Values.Get
只返回第一个值(详见https://godoc.org/net/url#Values.Get)。
编辑:我添加了处理结构体中指针的代码。它们需要特殊处理。
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)
}
希望对你有帮助!
英文:
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)
}
答案2
得分: 0
我终于成功使用了这个库,它可以将一个map转换为struct。唯一的问题是,我需要对URL.Query() Values
返回的map进行预处理,因为它对每个值返回一个数组,而我只需要值,而不是数组中的值。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论