# #http #go #query-parameters #go-gin
Вопрос:
Я использую веб-фреймворк Gin и пытаюсь найти способ связать список значений, разделенных запятыми, из параметра запроса в структуру. Ниже приведен фрагмент моего кода:
type QueryParams struct {
Type []string `form:"type"`
}
func BulkRead(c *gin.Context) {
params := QueryParams{
Type: []string{},
}
if err := c.ShouldBindQuery(amp;params); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't bind query params"})
return
}
c.Status(200)
}
Запрос: GET /api/v1/car?type=ford,audi
Чего я ожидаю: ["ford", "audi"]
Что я получаю: "ford,audi"
Есть ли простой способ сделать это? Или мне нужно будет написать пользовательскую функцию для обработки этого?
Комментарии:
1. Я думаю, вам, вероятно, нужно будет использовать
GetQueryArray
.2. Я попробовал это сделать, но это все равно не дает мне того результата, который я ищу,
arr, _ := c.GetQueryArray("type"); fmt.Println(arr[0])
— >"ford,audi"
3. Функция никак не может узнать, ожидаете ли вы несколько значений, разделенных запятой (почему не двоеточие или другой символ?). Возможно, следующий запрос будет автоматически работать в любом http-маршрутизаторе:
GET /api/v1/cart?type=fordamp;type=audi
4. Возможно, rsql является более подходящим решением для вашего API
Ответ №1:
Для извлечения значений, разделенных запятыми, из параметра запроса вы можете использовать Split()
метод из strings
пакета .Я создал простую программу для вашего сценария следующим образом :
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
var cars []string
qryResult := "ford,audi"
carBrands := strings.Split(qryResult, ",")
fmt.Println(carBrands)
for i := 0; i < len(carBrands); i {
cars = append(cars, strconv.Quote(carBrands[i]))
}
fmt.Println(cars)
}
Выход:
[ford audi]
["ford" "audi"]
Ответ №2:
У Джина нет способа сделать это за тебя. Самое простое решение-просто получить параметры запроса и разделить его самостоятельно. Это буквально 2 строки кода:
func MyHandler(c *gin.Context) {
ss := strings.Split(c.Query("type"), ",")
fmt.Println(ss) // [ford audi]
qp := QueryParams{
Type: ss,
}
}
Если у вас есть возможность изменить способ выполнения запроса, измените его на:
GET /api/v1/car?type=fordamp;type=audi
(повторите ключ запроса)
или URL-кодируйте запятую:
GET /api/v1/car?type=ford audi
( ,
->
)
Тогда context.GetQueryArray
все будет работать так, как вы ожидаете:
func MyHandler(c *gin.Context) {
cars, _ := c.GetQueryArray("type")
fmt.Println(cars) // [ford audi]
}
Конечно, реализация вашей собственной binding.Binding
-это вариант, подходящий, если у вас есть больше, чем просто этот параметр запроса, и вы хотите инкапсулировать логику привязки в одном месте, но я чувствую, что это излишне для вашего варианта использования:
type commaSepQueryBinding struct {}
func (commaSepQueryBinding) Name() string {
return "comma-sep-query"
}
func (commaSepQueryBinding) Bind(req *http.Request, obj interface{}) error {
values := req.URL.Query()
p := obj.(*QueryParams)
p.Type = strings.Split(values["type"][0], ",")
return nil
}
func MyHandler(c *gin.Context) {
q := QueryParams{}
err := c.ShouldBindWith(amp;q, amp;commaSepQueryBinding{})
if err != nil {
panic(err)
}
fmt.Println(q.Type) // [ford audi]
}
Ответ №3:
Такого способа может и не быть. Обычно я делаю это:
type QueryParams struct {
Type string `form:"type"`
}
func (q *QueryParams) Types() []string {
return strings.Split(q.Type, ",")
}
func BulkRead(c *gin.Context) {
params := new(QueryParams)
if err := c.ShouldBindQuery(amp;params); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't bind query params"})
return
}
c.JSONP(200, map[string]interface{}{
"types": params.Types(),
})
}
Ответ №4:
Это может быть полезно и для вас тоже.
package main
import (
"log"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
type TypeBinding struct {
name string
}
func NewTypeBinding(name string) *TypeBinding {
return amp;TypeBinding{
name: name,
}
}
func (t *TypeBinding) Name() string {
return t.name
}
func (t *TypeBinding) Bind(r *http.Request, i interface{}) error {
ttype := r.URL.Query().Get(t.name)
ii := i.(*QueryParams)
ii.Type = strings.Split(ttype, ",")
return nil
}
type QueryParams struct {
Type []string `url:"type"`
}
func ggin() {
router := gin.Default()
typeBinding := NewTypeBinding("type")
var opt QueryParams
router.GET("/", func(c *gin.Context) {
if err := c.MustBindWith(amp;opt, typeBinding); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't bind query params"})
return
}
log.Printf("type: %v", opt.Type)
c.String(http.StatusOK, "type: %s", opt.Type)
})
router.Run(":8080")
}