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

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.

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.

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

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)

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
}
// ...

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

Getting the URL parameter in Go issue

I have a URL that looks something like this: http://localhost/templates/verify?key=ijio
My router looks like this:
import (
"github.com/gorilla/mux"
"github.com/justinas/alice"
)
ctx := &model.AppContext{db, cfg} // passes in database and config
verifyUser := controller.Verify(ctx)
mx.Handle("/verify", commonHandlers.ThenFunc(verifyUser)).Methods("GET").Name("verify")
I want to get the key parameter out of the URL, so I use the following code:
func Verify(c *model.AppContext) http.HandlerFunc {
fn := func(w http.ResponseWriter, r *http.Request) {
key := r.URL.Query().Get("key") // gets the hash value that was placed in the URL
log.Println(key) // empty key
log.Println(r.URL.Query()) // returns map[]
// code that does something with key and sends back JSON response
}
}
I used AngularJS to get the JSON data:
app.controller("verifyControl", ['$scope', '$http', function($scope, $http) {
$scope.message = "";
$http({
method: 'GET',
url: "/verify"
}).success(function(data) {
$scope.message = data.msg; // JSON response
});
}]);
However, I end up with an empty key variable when I try to print it out. I recently used nginx to take out my .html extension if that's a possible cause of this problem. How do I fix this?
The solution to my question involves inspecting the request URL link by
log.Print(r.URL) // This returns "/verify"
However, that's not exactly what you want. Instead, you want the full URL. You can do the following to get the full URL and extract the parameter from it:
urlStr := r.Referer() // gets the full URL as a string
urlFull, err := url.Parse(urlStr) // returns a *URL object
if err != nil {
log.Fatal(err)
return
}
key := urlFull.Query().Get("key") // now we get the key parameter from the URL
log.Println("Key: " + key) // now you'll get a non empty string

Resources