Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert URL.Query (map of slices) to struct golang

Tags:

struct

go

It would be awesome to have a straight forward mapping from the standard library URL.Query() to an struct.

Query() returns a map like: map[a:[aaaa] b:[bbbb] c:[cccc]]

The struct looks like:

type Thing struct {
    A    string
    B    string
    C    string
}
  • I've no idea why URL.Query returns a map with array elements inside tough. (well.. I know why but a GET is not likely to have duplicated params)
like image 774
Custodio Avatar asked Nov 12 '16 16:11

Custodio


3 Answers

Please find below the complete example of parsing get query params directly in a golang struct and then sending the struct back as response

package main

import (
    "log"
    "net/http"
    "encoding/json"
    "github.com/gorilla/schema"
)

var decoder  = schema.NewDecoder()

type EmployeeStruct struct {
    MemberId         string `schema:"memberId"`
    ActivityType     string `schema:"activityType"`
    BusinessUnitCode int    `schema:"businessUnitCode"`
}

func GetEmployee(w http.ResponseWriter, r *http.Request) {
    var employeeStruct EmployeeStruct

    err := decoder.Decode(&employeeStruct, r.URL.Query())
    if err != nil {
        log.Println("Error in GET parameters : ", err)
    } else {
        log.Println("GET parameters : ", employeeStruct)
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(employeeStruct)
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/GetEmployee", GetEmployee)
    log.Fatal(http.ListenAndServe(":8080", mux))
}

Steps to execute & Test (Assuming you are saving above code in employee.go) :

Step 1 : go run employee.go

Step 2 : Open in browser http://localhost:8080/GetEmployee?memberId=123&activityType=Call&businessUnitCode=56

Step 3 : You should get below response in browser window

{
    "MemberId": "123",
    "ActivityType": "Call",
    "BusinessUnitCode": 56
}

Step 4 : On console you should see below

GET parameters :  {123 Call 56}
like image 102
Nikhil Maheshwari Avatar answered Nov 19 '22 21:11

Nikhil Maheshwari


example:

filters={"reference":["docker.io/library/alpine:latest"]}

need url encode to:

filters=%7B%22reference%22%3A%5B%22docker.io%2Flibrary%2Falpine%3Alatest%22%5D%7D

and could use "github.com/gorilla/schema"

    query := struct {
        All     bool
        Filters map[string][]string `schema:"filters"`
        Digests bool
        Filter  string 
    }{}
    decoder := schema.NewDecoder()
    decoder.Decode(&query, r.URL.Query())
like image 29
张馆长 Avatar answered Nov 19 '22 20:11

张馆长


As pointed out by @mh-cbon gorilla schema is the ultimate solution here.

Instead for obtaining the queryParams from the URL attribute.

func handleRequest(w http.ResponseWriter, r *http.Request) {
    queryString := r.URL.Query()
    //...parsing the Values -> map[string][]string
}

The approach of gorilla schema is to ship r.PostForm to the decode function.

func handleRequest(w http.ResponseWriter, r *http.Request) {
    err := decoder.Decode(person, r.PostForm)
    //...using reflect each struct's property can be called using 
    // the PostForm(url string, data url.Values) signature

    fmt.Print(person.GoodJobGorilla)
}
like image 2
Custodio Avatar answered Nov 19 '22 22:11

Custodio