IBM Cloud Functions WebAction gives empty response (204) - openwhisk

I am running into strange behavior with IBM Cloud Functions.
I have an Action that is web enabled (WebAction) for which I don't require authentication.
I use Postman (and a browser) to test this new REST endpoint.(left side of the image below)
The result is empty, an actual 204 No Content reponse.
But when I monitor the Action, I can see that it has been invoked and returned the expected JSON (right side of the image below). So the code is executed correctly.
When I perform a commandline invoke:
bx wsk action invoke --result talkToEoffice --param name FunctionWorld
I do see the expected result.
Should I provide additional headers ?
Does this have something todo with synchronous (blocking) or non-blocking ?

Looks like you’re returning an object with a property called greeting. For a webaction the response must include a property called body instead. You can nest greeting under body. See https://github.com/apache/incubator-openwhisk/blob/master/docs/webactions.md#handling-http-requests-with-actions for response requirements.

Related

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/

How to pass django error status to ajax

Using django rest framework with backbone.
Current situation:
Whenever an ajax call fails, django responds through get_error_response
As soon as get_error_response gets invoked, django raises a error on client side too, as i am not handling this error in django(server) side.
views.py snippet
def get_error_response(self):
return Response(
self.serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
Requirement:
I want to be able to pass all error statuses to $ajax.fail() promise, and handle it there on client side, thereby enabling me to show the error messages to user.
Note:something like the code given below is what i am expecting. But the problem is, this response would got to $ajax.done promise(), wheras i want it in $ajax.fail() promise
def get_error_response(self):
return Response({
"msg":self.serializer.errors, "error_status":status.HTTP_400_BAD_REQUEST
})
Do ask if more clarity is required.
No matter if you're using a Response from Django Rest Framework or the normal Django HttpResponse you always need to pass the keyworded argument status in order to make the response actually have the correct status code thus invoking the correct handler in your front end code.
What your last example does is only passing a data or content argument which is making the response class default to a 200 status code.
return Response(your_data, status=404)

Handling ajax errors with jsf.ajax.addOnError

How does jsf.ajax.addOnError actually catch errors?
I didn't find any information about it's mechanism. I only found that it is a error listener.
Wherever you've found the statement that jsf.ajax.addOnError is an error-listener, that source is wrong. The addOnError function adds an error listener (ie, a function you define yourself and that gets called whenever the JSF framework encounters an error situation).
This is straight out of the JSF-2.2 spec, 13.3.6.2:
The jsf.ajax.addOnError function accepts a JavaScript function argument that will be
notified when errors occur during any Ajax request/response cycle. [P1-start-event] The implementation must ensure the JavaScript function that is registered must be called in accordance with the errors outlined in Section TABLE 14-5 “Errors”.[P1-end]
Thus, the "errors" table defines under which conditions your function will get called. Here they are:
httpError: request status==null or request.status==undefined or request.status<200 or
request.status >=300
serverError: The Ajax response contains an “error” element.
malformedXML: The Ajax response does not follow the proper format.
emptyResponse: There was no Ajax response from the server.
JSF implementations basically fire a Ajax request and define internal handlers that get called by the browser when a response arrives. Then, they are required to inspect the response and if one the above conditions are met, they look up if you have registered any functions to be called and execute them if need be (they do a lot more, but that's the part in question here).

wireload / Ratatosk : How to make POST requests?

In my Cappuccino frontend I'm using Ratatosk to make queries to a RESTful JSON-based API.
When I create a new resource with
[myNewResource ensureCreated];
my backend returns the status code 201 and a Location header with the URI of the newly created resource. The response body is empty. As far as I know, that's the way a REST API should react to successful POST requests.
But upon receiving the response, Ratatosk calls
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
(in WLRemoteLink.j) and tries to decode the response body. This throws an error because the response body is empty. As a consequence, the request is repeated infinitely.
How should I go about this? Am I supposed to return the whole resource in the response body?
EDIT:
Returning the ID in the response solved the problem, like
{"id":1}
Ratatosk expects the status code 204 (no content) if the response is to be empty. Otherwise it expects the full representation of the resource which was just created (which it uses to populate server side dynamic properties locally like created_at).

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).

Resources