您好我想将查询参数转换为Go中的结构,例如我有这样的结构:
type Filter struct {
Offset int64 `json:"offset"`
Limit int64 `json:"limit"`
SortBy string `json:"sortby"`
Asc bool `json:"asc"`
//User specific filters
Username string `json:"username"`
First_Name string `json:"first_name"`
Last_Name string `json:"last_name"`
Status string `json:"status"`
}
我有可选参数,用户可以在发送Offset
,Limit
,SortBy
,Asc
,Username
的请求时指定这些参数,First_Name
,Last_Name
,Status
。
如果这些参数是在体内发送的,那么我会这样做:
b, err := ioutil.ReadAll(r.Body)
if err != nil {
log.WithFields(logFields).Errorf("Reading Body Message:failed:%v", err)
return
}
var filter Filter
err = json.Unmarshal(b, &filter)
但是我无法在GET
请求中发送正文,那么解决方案是什么,而不是单独获取每个参数然后将它们放入结构中?
答案 0 :(得分:5)
schema
包 github.com/gorilla/schema
软件包是为此而发明的。
您可以使用struct tags告诉如何将网址参数映射到结构字段,schema
包会查找"schema"
标记键。
使用它:
import "github.com/gorilla/schema"
type Filter struct {
Offset int64 `schema:"offset"`
Limit int64 `schema:"limit"`
SortBy string `schema:"sortby"`
Asc bool `schema:"asc"`
//User specific filters
Username string `schema:"username"`
First_Name string `schema:"first_name"`
Last_Name string `schema:"last_name"`
Status string `schema:"status"`
}
func MyHandler(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
// Handle error
}
filter := new(Filter)
if err := schema.NewDecoder().Decode(filter, r.Form); err != nil {
// Handle error
}
// Do something with filter
fmt.Printf("%+v", filter)
}
json
请注意,schema
包也会尝试将参数值转换为字段类型。
如果结构只包含[]string
类型的字段(或者您愿意做出妥协),则可以在没有schema
包的情况下执行此操作。
Request.Form
是map
,从string
到[]string
的映射(因为一个参数可能会在网址中多次列出:
Form url.Values
type Values map[string][]string
例如,如果您的Filter
结构看起来像这样:
type Filter struct {
Offset []string `json:"offset"`
Limit []string `json:"limit"`
SortBy []string `json:"sortby"`
// ..other fields
}
您只需使用json
包来封送r.Form
,然后将其解组到您的结构中:
func MyHandler(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
// Handle error
}
data, err := json.Marshal(r.Form)
if err != nil {
// Handle error
}
filter := new(Fiter)
if err = json.Unmarshal(data, filter); err != nil {
// Handle error
}
fmt.Printf("%+v", filter)
}
此解决方案处理是否为同一参数名称提供了多个值。如果你不关心多个价值观而你只想要一个,那么你首先要做的是转变" r.Form
改为map
个string
个值而不是[]string
。
这就是它的样子:
type Filter struct {
Offset string `json:"offset"`
Limit string `json:"limit"`
SortBy string `json:"sortby"`
// ..other fields
}
// Transformation from map[string][]string to map[string]string:
m := map[string]string{}
for k, v := range r.Form {
m[k] = v[0]
}
然后你可以将m
编组并以同样的方式将其解组到Filter
结构中。
答案 1 :(得分:0)
对于Echo
框架,您可以将查询字符串绑定到类似于此示例代码的结构。
type Filter struct {
Offset int64 `query:"offset"`
Limit int64 `query:"limit"`
SortBy string `query:"sortby"`
Asc bool `query:"asc"`
//User specific filters
Username string `query:"username"`
First_Name string `query:"first_name"`
Last_Name string `query:"last_name"`
Status string `query:"status"`
}
query := new(Filter)
if err := c.Bind(query); err != nil {
// handle error here
}
答案 2 :(得分:0)
支持:
per_page
、page_size
。示例代码:
type Authorization struct {
// Decode from multiple sources, the former with higher priority
Token string `in:"form=access_token;header=x-api-token;required"`
}
type Pagination struct {
Page int `in:"form=page"`
// Decode from multiple keys in the same source, the former with higher priority
PerPage int `in:"form=per_page,page_size"`
}
type ListUsersInput struct {
Gender string `in:"form=gender"`
AgeRange []int `in:"form=age_range"`
IsMember bool `in:"form=is_member"`
Pagination // Embedded field works
Authorization // Embedded field works
}
func ListUsers(rw http.ResponseWriter, r *http.Request) {
inputInterface, err := httpin.New(ListUsersInput{}).Decode(r)
if err != nil {
// Error occurred, `err` can be type of *httpin.InvalidFieldError
// Do sth.
return
}
input := interfaceInput.(*ListUsersInput)
// Do sth.
}