How to pass multiple arguments to golang net rpc call - go

I am using net library in go and I want to make RPC call:
Client.Call("action", []string{"arg1", "arg2"}, &response)
But in JSON I see:
{"method":"action","params":[["arg1","arg2"]],"id":0}
Notice that arguments are enclosed with double square brackets.
In my case I need params to be a simple list:
{"method":"action","params":["arg1","arg2"],"id":0}
Any ideas how to accomplish this?

The codec that Go's JSON RPC uses on top of the rpc.Client will take whatever param you send and encode that as the first element of the array it uses for the params.
So the encoded request will always have a top level array with just one element, which will contain the params you sent, as you already noted.
See the WriteRequest function here:
https://golang.org/src/net/rpc/jsonrpc/client.go#L57
To achieve what you want, you can implement a custom rpc.ClientCodec.
The interface is documented here:
https://golang.org/pkg/net/rpc/#ClientCodec
You can borrow almost all of the implementation for the default JSON codec here:
https://golang.org/src/net/rpc/jsonrpc/client.go
And modify the params attribute of the request to read:
Params interface{} `json:"params"`
Then when writing your WriteRequest based on the standard one, you can just assign your params to the request params:
c.req.Params[0] = param
You can then use the rpc.NewClientWithCodec to create a client using your custom codec:
https://golang.org/pkg/net/rpc/#NewClientWithCodec

Related

Why are Golang http arguments (URL.Query()) map of lists?

When we call
r.URL.Query()
Inside a http route handler handler in Go, it returns a map[string][]string. I am wondering why is it a list and if I can use this property somehow when sending requests.
It is a list because it is allowed to send multiple copies of the same query string parameter in a URL, and yes, you can send query string parameters in requests.
E.g. for a URL like http://example.com/?foo=1&foo=2, Query() would return:
{"foo": ["1","2"]}

How to inject a header from the errormessage

I've been attempting to inject a custom header for a error response status (and failing).
I have a very simple lambda being used
exports.handler = (event, context, callback) => {
// TODO implement
//callback(null, 'Hello from Lambda');
var error = {
name:"error",
message:"I am a failure",
statusCode: 400
};
error["x-test"] = 'foo';
callback(JSON.stringify(error), null);
};
In the api gateway, I've done the following:
set up CORS to include x-test
responsetemplate = "$input.path('$.errorMessage')"
responseparameter to include:
method.response.header.x-test = integration.response.body.x-test
Also, I have a statusCode mapped using '.*statusCode.*?400.*'
This has turned out empty.
so I decided to take a step back and see what happens if I do:
method.response.header.x-test = integration.response.body
I found that I get the stringified response of errorMessage.
{"x-test":"{\"errorMessage\":\"{\\\"name\\\":\\\"error\\\",\\\"message\\\":\\\"I am a failure\\\",\\\"statusCode\\\":400,\\\"x-test\\\":\\\"foo\\\"}\"}"}
So I decided to change the responsetemplate to force it to json by doing the following:
responsetemplate = "$util.parseJson($input.path('$.errorMessage'))"
and I still get the stringified response:
{"x-test":"{\"errorMessage\":\"{\\\"name\\\":\\\"error\\\",\\\"message\\\":\\\"I am a failure\\\",\\\"statusCode\\\":400,\\\"x-test\\\":\\\"foo\\\"}\"}"}
My guess is that it doesn't transform as expected, but only for the final output.
So how would you take a value and shove it into a header?
Thanks,
Kelly
I think this is more of a design choice regarding the limitation imposed by both Lambda and APIGateway. I will try my best to walk through my thoughts.
First of all, in Lambda, callback(error, result) function can either take an error string as first argument, or an object as result response. If you want to pass along a simple error message, you could definitely just do that. However, in your case, as you tried to pass along an entire error object, choosing the second option is clearly a better solution (in contrast to stringifying an object and parse it into object again). As a result, the final line of your Lambda function should be:
callback(null, error);
Yes, in this case, if you test your function in Lambda, the output result will no longer be red and flag it as an error, but this won't matter as you can format your headers and response in APIGateway.
Now you need to set things up in APIGateway, in which you need to make use of the object passed by Lambda.
It's actually rather easy to use method execution interface to configure headers.
In Method Response, you need to add the headers you want to include in the response for a specific status code, which in your case is x-test. (If you want the API to return different status codes, you can also configure that in this panel.)
Then go to Integration Response, under the same status code, you will see the added header available. According to this documentation from AWS, you can use integration.response.body.JSONPath_EXPRESSION to assign the header value (this is another reason that you should return object rather than string in Lambda, as there is no formal API to parse object from string at this stage). This time, as your Lambda is passing an object, the value of x-test header is:
integration.response.body['x-test']
Now your API should have the proper header included.
NOTE: In order to set up different status code in APIGateway, you should leave some distinguishable data fields (your statusCode: 400 should work perfectly) in you response body, so you can use RegEx to match those fields to a specific status code.
So... above doesn't work with success message. I found this blog though talking about error handling design pattern. Apparently what they suggest is only mapping status code when there is an error, in which case no body should be passed (only the errorMessage), as browser won't care about response body for a status code other than 200 anyway.
I guess after all, it is impossible to customize both status code and header at the same time with Lambda passing an object to APIGateway?
This is due to the fact that you are stringifying the error object coming from your Lambda function. API Gateway attempts to resolve the JSON-Path expression and can't evaluate "x-test" in a string. If you return an object instead of a string, this should work.
You may want to consider using proxy integrations which allow you to control the headers and status directly from your Lambda function.
Update: I've written a blog post on this topic with sample code # https://rpgreen.wordpress.com/2017/01/25/how-to-send-response-headers-for-aws-lambda-function-exceptions-in-api-gateway/

Should a JSON-P callback function accept a string?

I'm calling a REST API somebody else created. It supports JSONP to facilitate cross domain access.
The response I get back from the service looks like:
mycallback('{"token": "123456789"}');
Notice the single quotes wrapping the JSON data; Passing it as a string rather than a raw object. JQuery can handle this, but other libraries seem to expect a raw object instead.
mycallback({"token": "123456789"});
The raw object parameter makes more sense to me since it avoids the need to parse the JSON data, but I want to know for sure before asking the maintainer of the API to make the adjustment:
Which is most correct?
Passing a javascript literal (second) as shown here is more correct as it avoids deserializing the string back to a javascript object.
Passing a string is obviously a bad thing - you have two choices (#1 is preferred):
Ask the developer of the JSONP service to send proper JSONp instead of a string
Make your callback function smart so it uses something like payload = JSON.parse(payload); in case payload is a string.

Flex 4 - Sending string (such as JSON) using HTTPService

When I use HTTPService.send(paramter) as a POST request, the web server does not appear to see variable "parameter" if it is a string. The server sees the parameter if it's an Object, but I'm looking to use something like httpservice.send(JSON.encode(object)); Is this possible?
Why not use the actual request objects.
in your service define request objects and post them or send them as get if you please.
Sample code here: http://pastebin.com/ft7QW2vg
Then just call .send on the service.
on the server you can simlpy process if with request.form (Asp)
Failing which why not append it to the url with a binding expression. (you would need to encode it since you would be more or less faking a url or a get behaviour).

jQuery POST and GET methods: Construct URL or use data param?

I am using the post and get methods for Ajax calls, and have a general question. There are two methods I've seen people use on the web:
Construct the URL and parameters by
hand
Use the data parameter
Both approaches work. I've included them below:
// Construct the POST URL by hand
queryStringDelimiter = "?";
settings.queryParam = "q";
$.post(settings.url + queryStringDelimiter + settings.queryParam + "=" + query, {}, callback, settings.contentType);
// Use the data param
$.post(settings.url, {q:query}, callback, settings.contentType);
Are there any situations where you would construct the URL and parameters by hand instead of using the built-in data parameter? Any advantages of one method over the other?
I'd say the data approach is better since it formalizes the process and reduces the chances of producing errors while string building. Besides, the JQuery library will do the string building for you so its basically the same amount of work.
No reason I can think of why one would construct them by hand unless they didn't know of the data parameter if there's more than 1 or 2 parameters, it's also cleaner to keep them separated so if you have to loop through the data object and possibly modify some values you'd just iterate over the object instead of parsing a string manually.
If you let jQuery concatenating the data in to the appropriately formatted string you...
avoid having to duplicate that code...
avoid worrying about escaping the data for transport...
can easily switch between GET and POST requests in the future...
Really, the only argument AGAINST using the data parameter is if you already have the data in a concatenated format.
If I am using a GET I tend to just construct the URL, but when using POST I use the data parameter.
I do it because it is closer to how I was doing ajax calls before jQuery, when I wrote everything myself.

Resources