How to get all GET request query parameters into a structure in Go?

谁说我不能喝 提交于 2019-12-05 06:25:36
icza

Using gorilla's schema package

The github.com/gorilla/schema package was invented exactly for this.

You can use struct tags to tell how to map URL parameters to struct fields, the schema package looks for the "schema" tag keys.

Using it:

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)
}

Marshaling and unmarshaling using json

Note that the schema package will also try to convert parameter values to the type of the field.

If the struct would only contain fields of []string type (or you're willing to make that compromise), you can do that without the schema package.

Request.Form is a map, mapping from string to []string (as one parameter may be listed multiple times in the URL:

Form url.Values

And url.Values:

type Values map[string][]string

So for example if your Filter struct would look like this:

type Filter struct {
    Offset []string `json:"offset"`
    Limit  []string `json:"limit"`
    SortBy []string `json:"sortby"`
    // ..other fields
}

You could simply use the json package to marshal r.Form, then unmarshal it into your struct:

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)
}

This solution handles if multiple values are provided for the same parameter name. If you don't care about multiple values and you just want one, you first have to "transform" r.Form to a map with single string values instead of []string.

This is how it could look like:

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]
}

And then you can marshal m and unmarshal into it into the Filter struct the same way.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!