Why does PostForm Map structure parse data as the key of the map? - ajax

We have the following AJAX call to a golang endpoint:
var ajaxParams = {
type: 'POST',
url: '/golang_endpoint'
dataType: 'json',
processData: false,
timeout: timeout,
contentType: 'application/json',
data: JSON.stringify({"test": 1, "test2": "val"}),
};
$.ajax(ajaxParams);
However, req.PostForm looks like it was parsed incorrectly:
req.ParseForm()
fmt.Println(req.PostForm)
We get: map[{"test":1,"test2":"val"}:[]]
Why did ParseForm end up getting parsed this way? How can we parse it so that PostForm is of value map[test: [1] test2: [val]]
EDIT:
This is a potential solution:
var ajaxParams = {
contentType: 'application/json',
data: JSON.stringify({"test": 1, "test2": "val"}),
...
};
data, err := ioutil.ReadAll(req.Body)
var m map[string]interface{}
err = json.Unmarshal(data, &m)
fmt.Println(m)

Related

How to read custom ajaxParams in Golang http.Request object

We have the following ajaxParams:
var ajaxParams = {
type: 'POST',
url: '/golang_endpoint',
dataType: 'json',
customParam: 'customParam',
success: onResponse,
error: onError,
};
Is it possible for Golang to read the custom attribute as it appears in the form of an *http.Request object in the associated Golang handler?
Those parameters are used to do the AJAX request, they are not what actually gets to the server. You should pass it as the data of the POST request, as in:
var ajaxParams = {
type: 'POST',
url: '/golang_endpoint',
dataType: 'json',
data: {customParam: 'customParam'},
success: onResponse,
error: onError,
};
$.ajax(ajaxParams);
Then, on the Go side, you just handle the data as you want it, like in:
type MyStruct {
customParam string `json:"customParam"`
}
func HandlePost(w http.ResponseWriter, r *http.Request) {
dec := json.NewDecoder(r.Body)
var ms MyStruct
err := dec.Decode(&ms)
if err != nil {
panic(err)
}
fmt.Println(ms.customParam)
}
Assuming you want your param to be a string. Either way you could convert it to the type you want.

Golang Get all POST Form data using PostParams and get values as string

I want to get all the post form data and get the values as string, however using PostParams I am able to get all the post data, but the values are as array key: [value], how can I get all the form data as string values?
[Edit]
I may not stated clearly, but I need to get the whole form as JSON, because I need to send the form data to another API which need the body as JSON data
form.html
<form>
<input type='text' name='key' />
<input type='text' name='key2' />
</form>
script.js
$.ajax( {
url: '/post/action',
type: 'POST',
data: new FormData(this),
processData: false,
contentType: false
}).done(function(r) {
console.log(r);
});
action.go
func PostAction(c echo.Context) error {
form, _ := c.FormParams()
b, _ := json.Marshal(form)
log.Println(b) // this will print: key: [value], key2: [value]
// I want to get value as string: key: value, key2: value
// ..other function, return, etc
}
How can I get the form values as string?
Or is there another function that does this?
Thank you very much in advance
No need to JSON marshal the already decoded form, simply do:
form["key"][0]
form["key2"][0]
See the docs on c.FormParams and then click on the return type to see its documentation, and you'll notice that it's just the stdlib's url.Values type, which is defined as a map of string slices (i.e., map[string][]string).
If you need to convert a value of type url.Values to a "simple object", you can convert it to a map[string]string using the following code:
o := make(map[string]string, len(form))
for k, v := range form {
// if you are certain v[0] is present
o[k] = v[0]
// if you are not sure v[0] is present, check first
if len(v) > 0 {
o[k] = v[0]
}
}
data, err := json.Marshal(o)
if err != nil {
return err
}
// ...

Send arbitrary JSON to gorilla websocket connection

I have the following function where I want to send arbitrary JSON data to a websocket connection. The data depends on what was sent to the server. How this can be achieved without creating different structs for each thing I want to send?
I am thinking about something like this:
func Register(c *websocket.Conn, m WebsocketGeneralClientMessage) {
var d RegisterData
json.Unmarshal(m.Data, &d)
if len(d.Email) < 6 || len(d.Email) > 64 {
c.WriteJSON(WebsocketGeneralServerMessage{
Type: "error", Data: map[string]interface{"text": "This is an error"}})
return
}
if len(d.Password) < 6 || len(d.Password) > 32 {
c.WriteJSON(WebsocketGeneralServerMessage{
Type: "error", Data: map[string]interface{"text": "This is another error"}})
return
}
err := checkmail.ValidateFormat(d.Email)
if err != nil {
c.WriteJSON(WebsocketGeneralServerMessage{
Type: "error", Data: map[string]interface{"text": "This is different than all the previous errors"}})
return
}
uuid, email, password, err := DB.RegisterAccount(requestEmail, requestPassword)
if err != nil {
c.WriteJSON(WebsocketGeneralServerMessage{
Type: "error", Data: map[string]interface{"text": "An error occured while saving the account to the database"}})
return
}
c.WriteJSON(WebsocketGeneralServerMessage{
Type: "success", Data: map[string]interface{"uuid": uuid}})
return
}
type WebsocketGeneralServerMessage struct {
Type string
Data map[string]interface{}
}
However, the compiler says:
syntax error: unexpected literal "text", expecting method or interface name
so it seems this syntax is not valid. What can be done here?
It's map[string]interface{}{"text": .... You missed the {}.

How to publish task by name to a RabbitMQ queue in Go?

I need to publish a task by name (creating a message on a queue with task name passed in headers, passing some args).
I've done this in Celery (Python) like this:
celery_app.send_task("task_name", args=("arg1", "arg2",))
Here's my code in Go to do the same thing:
headers := make(amqp.Table)
headers["argsrepr"] = []string{"arg1", "arg2"}
headers["task"] = "task_name"
body := ""
jsonBody, _ := json.Marshal(body)
err = ch.Publish(
"", // exchange
"queue_name", // routing key
false, // mandatory
false, // immediate
amqp.Publishing {
DeliveryMode: amqp.Persistent,
ContentType: "application/json",
Body: jsonBody,
Headers: headers,
})
But I get this error:
Failed to publish a message: table field "argsrepr" value [%!t(string=arg1) %!t(string=arg2)] not supported
I'm using "github.com/streadway/amqp" library to talk with my rabbitmq node. It seems that "send task by name" is not implemented in this library.
Here is an illustration of the symptoms. The fmt format string is apparently expecting boolean values.
package main
import "fmt"
func main() {
s := fmt.Sprintf("%t %t", "arg1", "arg2")
fmt.Println(s)
t := fmt.Sprintf("%t %t", true, false)
fmt.Println(t)
}
Output:
%!t(string=arg1) %!t(string=arg2)
true false

Golang, Ajax - How to return slices or struct in a success function?

My problem is similar to that of the question in this link. I need to return multiple slices or a struct from golang to the ajax success block. I tried to marshal my slice into JSON but it is received in ajax as a string. I need to receive it as an array. Is it possible to send multiple arrays or a struct like this?
My code:
b, _ := json.Marshal(aSlice) // json Marshal
c, _ := json.Marshal(bSlice)
this.Ctx.ResponseWriter.Write(b) // Beego responsewriter
this.Ctx.ResponseWriter.Write(c)
My ajax:
$.ajax({
url: '/delete_process',
type: 'post',
dataType: 'html',
data : "&processName=" + processName,
success : function(data) {
alert(data);
alert(data.length)
}
});
Thanks in advance.
The dataType parameter of your ajax request should be json as you are expecting JSON data from the server. But if you server does not respond with valid JSON the ajax request is going to result in an error. Check your browser's javascript console for errors.
From what you are currently doing in the controller, its definitely going to result in invalid JSON response. See following.
aSlice := []string{"foo", "bar"}
bSlice := []string{"baz", "qux"}
b, _ := json.Marshal(aSlice) // json Marshal
c, _ := json.Marshal(bSlice)
this.Ctx.ResponseWriter.Write(b) // Writes `["foo","bar"]`
this.Ctx.ResponseWriter.Write(c) // Appends `["baz","qux"]`
This results in sending ["foo","bar"]["baz","qux"] Thats just two JSON array strings appended together. Its not valid.
What you probably want to send to browser is this: [["foo","bar"],["baz","qux"]].
That is an array of two arrays. You can do this to send it from the server.
aSlice := []string{"foo", "bar"}
bSlice := []string{"baz", "qux"}
slice := []interface{}{aSlice, bSlice}
s, _ := json.Marshal(slice)
this.Ctx.ResponseWriter.Write(s)
And in the javascript side,
$.ajax({
url: '/delete_process',
type: 'post',
dataType: 'json',
data : "&processName=" + processName,
success : function(data) {
alert(data);
alert(data[0]); // ["foo","bar"]
alert(data[1]); // ["baz","qux"]
alert(data.length) // 2
}
});
The answer of #AH works really well for multiple slices. Now if you want a Struct you should change a little bit your code :
package controllers
import "github.com/astaxie/beego"
import "encoding/json"
type Controller2 struct {
beego.Controller
}
type Controller2Result struct {
Accommodation []string
Vehicle []string
}
func (this *Controller2) Post() {
var result Controller2Result
aSlice := []string{"House", "Apartment", "Hostel"}
bSlice := []string{"Car", "Moto", "Airplane"}
result.Accommodation = aSlice
result.Vehicle = bSlice
s, _ := json.Marshal(result)
this.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json")
this.Ctx.ResponseWriter.Write(s)
}
Ajax
$.ajax({
url: '/Controller2',
type: 'post',
dataType: 'json',
//data : "&processName=" + processName,
success : function(data) {
alert(JSON.stringify(data));
}
});
How is explained here alert only can display strings and datais a object type of JavaScript. So you have to use JSON.stringify to turn object into JSON-String.

Resources