Как получить все параметры запроса GET request в структуру в Go?
Привет я хочу преобразовать параметры запроса get в структуру в 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"`
}
и у меня есть дополнительные параметры, которые пользователь может указать при отправке запроса get, которые являются 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
запрос так что решение вместо того, чтобы получать каждый параметр отдельно, а затем помещать их в структуру?
1 ответов
использование гориллы schema
пакета
на github.com/gorilla/schema
пакет был изобретен именно для этого.
можно использовать теги структуры чтобы рассказать, как сопоставить параметры URL с полями структуры,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)
}
маршалинг и unmarshaling с помощью json
отметим, что schema
package также попытается преобразовать значения параметров в тип поля.
если структура будет содержать только поля []string
тип (или вы готовы пойти на этот компромисс), вы можете сделать это без schema
пакета.
Request.Form
это map
, картографическая от string
to []string
(как один параметр может быть указан несколько раз в URL:
Form url.Values
и 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
, затем unmarshal его в вашу структуру:
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
struct таким же образом.