Nested values in url.Values - http

I'm working on an API client and I need to be able to send a nested JSON structure with a client.PostForm request. The issue I'm encountering is this:
reqBody := url.Values{
"method": {"server-method"},
"arguments": {
"download-dir": {"/path/to/downloads/dir"},
"filename": {variableWithURL},
"paused": {"false"},
},
}
When I try to go build this, I get the following errors:
./transmission.go:17: syntax error: unexpected :, expecting }
./transmission.go:24: non-declaration statement outside function body
./transmission.go:26: non-declaration statement outside function body
./transmission.go:27: non-declaration statement outside function body
./transmission.go:29: non-declaration statement outside function body
./transmission.go:38: non-declaration statement outside function body
./transmission.go:39: syntax error: unexpected }
I'm wondering what the correct way to created a nested set of values in this scenario. Thanks in advance!

I was able to figure this out on my own! The answer is to struct all-the-things!
type Command struct {
Method string `json:"method,omitempty"`
Arguments Arguments `json:"arguments,omitempty"`
}
type Arguments struct {
DownloadDir string `json:"download-dir,omitempty"`
Filename string `json:"filename,omitempty"`
Paused bool `json:"paused,omitempty"`
}
Then, when creating your PostForm:
jsonBody, err := json.Marshal(reqBody) // reqBody is a Command
if (err != nil) {
return false
}
req, err := http.NewRequest("POST", c.Url, strings.NewReader(string(jsonBody)))
Hope this helps!

You are not using properly the url.Values, according to the source code (url package, url.go):
// Values maps a string key to a list of values.
// It is typically used for query parameters and form values.
// Unlike in the http.Header map, the keys in a Values map
// are case-sensitive.
type Values map[string][]string
But arguments is not compliant with the definition because the object of arguments is not an array of strings.

I used NewRequest as Connor mentions in his answer but using a struct and then marshalling it seems an unnecessary step to me.
I passed my nested json string straight to strings.NewReader:
import (
"net/http"
"strings"
)
reqBody := strings.NewReader(`{
"method": {"server-method"},
"arguments": {
"download-dir": {"/path/to/downloads/dir"},
"paused": {"false"},
},
}`)
req, err := http.NewRequest("POST", "https://httpbin.org/post", reqBody)
Hope it helps those who are stuck with Go's http PostForm which only accepts url.Values as argument while url.Values cannot generate nested json.

Related

How to add URL query parameters to HTTP GET request?

I am trying to add a query parameter to a HTTP GET request but somehow methods pointed out on SO (e.g. here) don't work.
I have the following piece of code:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "/callback", nil)
req.URL.Query().Add("code", "0xdead 0xbeef")
req.URL.Query().Set("code", "0xdead 0xbeef")
// this doesn't help
//req.URL.RawQuery = req.URL.Query().Encode()
if err != nil {
log.Fatal(err)
}
fmt.Printf("URL %+v\n", req.URL)
fmt.Printf("RawQuery %+v\n", req.URL.RawQuery)
fmt.Printf("Query %+v\n", req.URL.Query())
}
which prints:
URL /callback
RawQuery
Query map[]
Any suggestions on how to achieve this?
Playground example: https://play.golang.org/p/SYN4yNbCmo
Check the docs for req.URL.Query():
Query parses RawQuery and returns the corresponding values.
Since it "parses RawQuery and returns" the values what you get is just a copy of the URL query values, not a "live reference", so modifying that copy does nothing to the original query. In order to modify the original query you must assign to the original RawQuery.
q := req.URL.Query() // Get a copy of the query values.
q.Add("code", "0xdead 0xbeef") // Add a new value to the set.
req.URL.RawQuery = q.Encode() // Encode and assign back to the original query.
// URL /callback?code=0xdead+0xbeef
// RawQuery code=0xdead+0xbeef
// Query map[code:[0xdead 0xbeef]]
Note that your original attempt to do so didn't work because it simply parses the query values, encodes them, and assigns them right back to the URL:
req.URL.RawQuery = req.URL.Query().Encode()
// This is basically a noop!
You can directly build the query params using url.Values
func main() {
req, err := http.NewRequest("GET", "/callback", nil)
req.URL.RawQuery = url.Values{
"code": {"0xdead 0xbeef"},
}.Encode()
...
}
Notice the extra braces because each key can have multiple values.

Convert string value to function call

I want to specify a function based on a string. I'm getting strings out of a map, in the example below they are the values in function while interating ove the map. Now for example, when the string value function == "networkInfo", I would like to "treat" that value as a real functions' name. It's hard to explain, but I think you guys will know what I mean.
My goal is to remove the switch statement and directly call c.AddFunc(spec, func() { networkInfo() }) where networkInfo is the function name, extracted from string function. I know this is possible, but I don't know how :(. Help is appreciated!
// ScheduleCronjobs starts the scheduler
func ScheduleCronjobs() {
tasks := props.P.GetStringMapString("tasks")
log.Infof("number of tasks: %d", len(tasks))
if len(tasks) != 0 {
c := cron.New()
// for each task, initialize
for function, spec := range tasks {
switch function {
case "networkInfo":
c.AddFunc(spec, func() { networkInfo() })
case "bla":
c.AddFunc(spec, func() { bla() })
default:
log.Errorf("unknown task: %q", function)
}
}
c.Start()
}
// after initialization, send out confirmation message
slack.SendMessage("tasks initialized", props.P.GetString("channel"))
}
Why not something like:
taskDefs := map[string]func(){
"networkInfo": networkInfo,
"bla": bla,
}
for function, spec := range tasks {
if fn, ok := taskDefs[function]; ok {
c.AddFunc(spec, func() { fn() }) // not sure if you need the enclosing func
} else {
log.Errorf("unknown task: %q", function)
}
}
If you do need varying signatures of your funcs then you'd actually need reflection, but if the types of the funcs are all the same, then using this map approach might be a simpler solution, without the overhead of reflection.
The only way I've found to find functions by name in a package is by actually parsing the source files. This repo is an example of finding funcs and storing them in a map with the name as the key.
The Go linker will silently drop unreferenced funcs, so if the only way you're referencing the func is through reflection it would break. That is why the map approach I suggest is superior; it let's the linker know the func is being used.

Passing an struct to a Post martini routine

I have an issue using this statement
m.Post(Model, binding.Form(Wish), func(wish Wish, r render.Render, db *mgo.Database) {
This worked fine if I use the struct define inside the prog like
m.Post(Model, binding.Form(Wish1{}) , func(wish Wish1, r render.Render, db *mgo.Database) {
but I need this to be an independent package.
I get "Wish is not a type" wish is the return of the binding function.
This worked with a primary Type struct. I am passing the strut as a interface{}
I am using GO with Martini.Classic() It is really complicated for me to change Martini or Binding package. Any suggestions.
This is the all code
package chlistpkg
import (
"github.com/codegangsta/martini"
"github.com/codegangsta/martini-contrib/binding"
"github.com/codegangsta/martini-contrib/render"
"labix.org/v2/mgo"
"time"
"fmt"
"html/template"
"reflect"
"adminStruct"
)
just to show the struct that I need to pass as to routine Doall
type Wish1 struct {
Name string `form:"name"`
Description string `form:"description"`
AnyDate time.Time `form:"anydate"`
Active bool `form:"active"`
Number int `form:"number"`
NumDec float32 `form:"numDec"`
}
DB Returns a martini.Handler
func DB() martini.Handler {
session, err := mgo.Dial("mongodb://localhost")
if err != nil {
panic(err)
}
return func(c martini.Context) {
s := session.Clone()
c.Map(s.DB("advent2"))
defer s.Close()
c.Next()
}
}
GetAll returns all Wishes in the database
func GetAll(db *mgo.Database, entList interface{}) interface{} {
db.C("wishes").Find(nil).All(entList)
fmt.Println("GettAll entList =", entList)
return entList
}
func Doall(Model string, Wish interface{}, Wish2 interface{}, Wishlist interface{} ) {
m := martini.Classic()
fmt.Println ("martini.Classic =", m)
m.Use(martini.Static("images")) // serve from the "images" directory as well
m.Use(render.Renderer(render.Options{
Directory: "templates",
Layout: "layout",
}))
m.Use(DB())
m.Get(Model, func(r render.Render, db *mgo.Database) {
r.HTML(200, "lista4", GetAll(db, Wishlist))
})
binding does not take a pointer. I have to pass the struct by reference on "Wish"
the issue is the return on "wish Wish" I got an error Wish is not a type
at compilation time
m.Post(Model, binding.Form(Wish), func(wish Wish, r render.Render, db *mgo.Database) {
fmt.Println("Input wish =", wish)
db.C("wishes").Insert(wish)
r.HTML(200, "lista4", GetAll(db, Wishlist))
})
m.Run()
Thanks in advance
Luis
The reason you are getting an error is that you have called your type Wish1 (with a numerical 1) but you are referring to the Wish type (which does not exist!) in your code.
Change your struct to be:
// Note: "Wish", not "Wish1"
type Wish struct {
Name string `form:"name"`
Description string `form:"description"`
AnyDate time.Time `form:"anydate"`
Active bool `form:"active"`
Number int `form:"number"`
NumDec float32 `form:"numDec"`
}
If you want to put your type into another package (tip: don't overdo the sub-packages), then it will need to become a pkgname.Wish as names are fully qualified.
Added
After a second look, you're also messing things up here:
func Doall(Model string, Wish interface{}, Wish2 interface{}, Wishlist interface{} ) {
m := martini.Classic()
fmt.Println ("martini.Classic =", m)
m.Use(martini.Static("images")) // serve from the "images" directory as well
Your parameter list needs to provide a name for each type; you can't pass Wish interface{} as a parameter as Wish is a type, not a variable name.
You should either:
func DoAll(model string, wish interface{}, wish2 interface{}, wishList interface{}) { ... }
Or, better still, stop using interface{} like this and write:
func DoAll(model string, wishList []Wish, wishes... Wish) { ... }
However, your DoAll function does not seem to be referenced elsewhere, and is creating its own Martini instance. I highly suggest thinking about why things are "split out" like this if you're just starting out. Keep it simple - e.g.
func main() {
m := martini.Classic()
m.Use(martini.Static("images"))
m.Use(DB())
m.Use(render.Renderer(render.Options{...}))
// No need for an anonymous function, which just adds clutter
m.Get("/wishes/all", GetAllWishes)
// Same goes for here
m.Post("/wishes/new", PostWish)
m.Run()
}
PS: I've fixed the formatting of your code, as it has a lot of unnecessary spacing before/after parenthesis. Make sure to use gofmt, which is included with the Go install and can be hooked into most popular editors.

How to force passing parameter as a pointer in Go?

I am implementing an application layer network protocol which uses JSON in Go.
func ReadMessage(conn net.Conn, returnMessage interface{}) bool {
messageBytes := // read from conn
error := json.Unmarshal(messageBytes, &returnMessage)
if error != nil {
return false
}
return true
}
The function takes a struct as its second parameter where the message is unmarshalled. The function can be called like this:
msg := MessageType1{}
ok := ReadMessage(conn, &msg)
Or without the ampersand (&)
msg := MessageType1{}
ok := ReadMessage(conn, msg)
which will compile, but not do what is should as the struct is passed as a copy, not as a reference and the original msg will remain empty. So I'd like to force passing the struct by reference and catch this error at compile time.
Changing the parameter type to *interface{} will not compile:
cannot use &msg (type *MessageType1) as type *interface {} in function argument:
*interface {} is pointer to interface, not interface
Is there some Go style way of doing this correctly?
There is not a way to do this in the function declaration.
You can use reflection though and panic at runtime when the argument is not a pointer.
However maybe you should consider changing the design of your code. The concrete type of the argument should not matter. It either implements the interface you need or not.
Demo: http://play.golang.org/p/7Dw0EkFzbx
Since Go 1.18 you can do this using generics:
func test[T any](dst *T) {
//Do something with dst
}
You can't enforce this as *T always has the method set of T. Thus both implement the interface.
From the spec:
The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).
What you can do instead is to use the language's ability to return multiple values in your function, as Volker already stated:
func ReadMessage(conn net.Conn) (interface{}, bool) {
var returnMessage interface{}
messageBytes := // read from conn
error := json.Unmarshal(messageBytes, &returnMessage)
if error != nil {
return nil, false
}
return returnMessage, true
}
You should also consider not returning type interface{} but some meaningful type.

Replace wrapping struct with a type declaration in Go

I want to extend the regexp from the Go standard library to be able to define my own methods. I use the following struct:
type RichRegexp struct {
*regexp.Regexp
}
As you can see, this struct contains nothing but the wrapped regexp.Regexp. So I wonder whether I could replace this with a simple type declaration like this:
type RichRegexp regexp.Regexp
But how should I write the following func then?
func Compile(expression string) (*RichRegexp, error) {
regex, err := regexp.Compile(expression)
if err != nil {
return nil, err
}
return &RichRegexp{regex}, nil // How to do this?
}
I tried to convert regexp.Regexp to my RichRegexp but it didn't compile. What is the general pattern to return a custom type which wraps a underlying type?
You can use a conversion, but in this case it is necessary, that your type definition is not a pointer:
type MyRegexp *regexp.Regexp // Doesn't work
This is backed by the spec:
The receiver type must be of the form T or *T where T is a type name.
The type denoted by T is called the receiver base type; it must not be
a pointer or interface type and it must be declared in the same
package as the method. The method is said to be bound to the base type
and the method name is visible only within selectors for that type.
However, you can do this:
type MyRegexp regexp.Regexp
As you're handling values now, you can do the following:
x := regexp.MustCompile(".*")
y := MyRegexp(*x)
And you have your own regexp type.
Full code at play: http://play.golang.org/p/OWNdA2FinN
As a general pattern, I would would say:
If it's unlikely to change and you don't need to store arbitrary values, use
a type conversion.
If you need to store values along with your embedded type, use a struct.
If your code is likely to change and needs to support large varieties of things,
define an interface and don't use embedding / type conversion.
package main
import (
"regexp"
)
type RichRegexp regexp.Regexp
func Compile(expression string) (*RichRegexp, error) {
regex, err := regexp.Compile(expression)
if err != nil {
return nil, err
}
return (*RichRegexp)(regex), nil
}
func main() {
Compile("foo")
}
Also here: http://play.golang.org/p/cgpi8z2CfF

Resources