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/
Related
I have built something that can capture network requests and save them to a file. Currently I am now trying to build the second part which should return these captured requests, but running into some difficulties. Sometimes I have multiple requests going to a single method/url combination, and I need to return a different response depending on the request body. The problem I am facing is illustrated in the example below:
cy.route({
url: 'api.example.com/**',
method: myMethod,
response: routeData => {
// I can set the response here
// But I don't have access to the request body
},
onRequest: xhr => {
// I can access the request body here
// But I am not supposed/able to set the response
},
})
If I understand the API docs correctly, I am supposed to set the response in the response callback. However, in that callback I do not seem to have access to the XHR object from which I could read the request body.
Is there a way to access the request body in the response callback?
Or, alternatively, is there a way to set the response from the onRequest callback?
Update: just saw this post which mentions a body property which can be added to the cy.route options object. I don't see this in the cypress route docs so I don't know if this is even a valid option, and I also wouldn't know if making multiple calls to cy.route with an identical method and url, but a different body would produce the correct results. If this was of any use, I would have hoped to have seen some branching logic based on a body property somewhere in this file, so I am not super hopeful.
Cypress v6 comes with the cy.intercept API. Using that is much more convenient than using cy.server and cy.route.
I'm converting an ASP.NET Web API project to ASP.NET Core WEB API. Before, we would return erroring responses like so:
throw new HttpResponseException(ErrorResponses.CreateErrorResponse(HttpStatusCode.Conflict, "Too many linked devices", new { status = (int)SignInStatus.TooManyLinkedDevices }));
Notice how we've set the http status code, an error message, and a response body. In Core, I can do this:
return Conflict("Too many linked devices");
However, I'm not seeing a way to also set the response body. What is the proper technique to achieve this?
I'm not sure what each param in the "old" code is corresponding to exactly, but there's only one response body, so logically, returning both a "Too many linked devices" string and an object is not possible. Either the string or the object was not actually being returned in the response body.
That said, your response body with Conflict is the param you're passing to it currently. That can either be an object (string is an object) or a ModelStateDictionary (i.e. ModelState). You probably need to do something like the following:
return Conflict(new {
message = "Too many linked devices",
status = (int)SignInStatus.TooManyLinkedDevices
})
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.
In Web API v2 when you supply data in the POST body that are not part of the model, they are ignored by the framework. This is fine in most cases, but I need to check this and return an error response, so the user doesn't get unexpected results (he expects these wrong parameters to do something...).
So how do I check for this? The model will be null, but when the framework has parsed the data and returned a null-model, I can no longer access the body through Request.Content. So what options are there?
One way is to derive your DTO class from DynamicObject. Check out my blog post: http://lbadri.wordpress.com/2014/01/28/detecting-extra-fields-in-asp-net-web-api-request/
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.