Description
Using node I make a typical API POST request for which I have a .catch block with response variable say err. On error, the response body is returned as such (as seen from the Hyperledger Composer REST app)
{
"error": {
"statusCode": 500,
"name": "Error",
"message": "error trying invoke chaincode. Error: chaincode error (status: 500, message: Error: Payment needs to be of positive value)",
"stack": "Error: error trying invoke chaincode. Error: chaincode error (status: 500, message: Error: Payment needs to be of positive value)\n at _initializeChannel.then.then.then.then.catch (/home/ubuntu/.nvm/versions/node/v6.11.1/lib/node_modules/composer-rest-server/node_modules/composer-connector-hlfv1/lib/hlfconnection.js:839:34)"
}
}
My Issue
I am simply trying to fetch the message property from the above response and send it to the UI. But weirdly err.message does not give me the value I see inside message but returns the entire response body(same with err.stack).
So basically -- err, err.message and err.stack returns the same output
How do I end up fetching only the value inside a property say message ?
PS:
err.statusCode does return the correct value ie. "500".
err.name returns "StatusCodeError"(not "Error" that I see in the response)
OK, so while not really a Hyperledger Composer question - you could try is it response.getBody() ? This is just an example, not a code snippet to use
var finalHost = "yoururl";
var r = new sn_ws.RESTMessageV2();
r.setHttpMethod("get");
r.setEndpoint(finalHost);
//r.setQueryParameter("locatenow", "true");
r.setBasicAuth(username,password);
var response = r.execute();
var responseBody = response.getBody();
// If response is in json format, directly you can send to client.
// If not then convert it.
return responseBody;
// On client side
var newoptions = JSON.parse(jsonstring);
// returned resp.
You might consider something like Restify for error handling on UI side ?
See README at bottom here https://github.com/restify/errors/blob/master/README.md ->
https://www.npmjs.com/package/restify-errors - see this S/O here
Related
I tried to send the below message
Invalid query parameters detected:
=== Error No. 1 ==========
Required property is missing
● Property / element: 'Deserialized query parameters of http://127.0.0.1:90/api/categories route.paginationPageNumber'
This property is 'undefined' while has been marked as required.
● Property / element specification:
{
"type": "number",
"required": true,
"numbersSet": "NATURAL_NUMBER"
}
● Actual value: undefined
● Value before first pre-validation modification: undefined
< etc. >
via
response. // (is "http.ServerResponse")
writeHead(HTTP_StatusCodes.badRequest, errorMessage).
end();
in errorMessage variable . Below NodeJS error occured:
Caught error:
TypeError [ERR_INVALID_CHAR]: Invalid character in statusMessage
at new NodeError (node:internal/errors:371:5)
at ServerResponse.writeHead (node:_http_server:322:11)
// ...
I have no idea on which character NodeJS complains about (possibly slashes), but I suppose what I am using the second parameter of writeHead improperly. If so, there are two questions:
Which errorMessage must be like? Just "Bad request" or "Unauthorized"?
Where I should append above login message instead?
You can refer to this for official documentation
You can send a response like this
let body = error_message; // or whatever response you want to send back to the sender
response
.writeHead(STATUS_CODE, {
'Content-Type': 'your_header_content_type'
}).end(body);
As for the status codes, you can refer the mozilla convention here (which is quite widely used)
I'd really like to be able to pass custom errors back out of my Lambda function via the API Gateway.
I'm generating the errors this way:
if (error) { // failure
APIGatewayResult = { // set error object
statusCode: 608,
message: 'File upload to buffer failed.',
error: error
};
done();
};
I'm fairly certain the format above is either parsed incorrectly or I can't pass it back out like this:
done = (err, res) => callback(null, {
statusCode: err ? APIGatewayResult.statusCode : APIGatewayResult.statusCode,
body: err ? JSON.stringify(APIGatewayResult) : JSON.stringify(APIGatewayResult),
headers: {
'Content-Type': 'application/json',
},
});
I'd like the response I get from API gateway to look like this:
{
"statusCode": 608,
"message": "File upload to buffer failed.",
"error": {}
}
Instead of this:
{
"message": "Internal server error"
}
There are two parts to your question:
1) How to handle Lambda error messages in API Gateway:
There are numerous guides available which explain how to parse Lambda error responses in API Gateway to return them in the desired format to consumers. For example: Error Handling Patterns in Amazon API Gateway and AWS Lambda.
Important to note that you're parsing null to the first parameter of the callback function from your lambda. The first parameter is the error response message, so by providing it as null the Lambda will be returning a successful 200 response back to API Gateway.
2) How to override the generic unhandled exception message in API Gateway:
This is required because as mentioned in the comments, the error you're receiving appears to have been thrown due to an unhandled exception in your application. You'll need to review the logs to identify the source of the issue.
But to change the format of the default error response object you'll need to add a custom Gateway response in API Gateway.
It's difficult to offer a more concrete example given the limited information provided but this should be enough to point you in the right direction to find what you're looking for.
Please guide me in case I'm not in proper use of axios. This simple piece of code can directly run:
const axios = require('axios')
axios.post('https://exp.host/--/api/v2/push/send', {"to":["ExponentPushToken[xxxxxxx]"],"title":"test title","body":"test body."})
.then(responseExpo => {
console.log("expo replied normally: " + JSON.stringify(responseExpo));
})
.catch(error => {
console.log("expo replied with error: " + JSON.stringify(error,null,4));
});
The result is:
Promise { <pending> }
expo replied with error: {}
"axios": "^0.19.2"
I tried to post with api tools and see a response with normal 200 status code:
{
"data":[
{
"status": "error",
"message": "\"ExponentPushToken[xxxxxxx]\" is not a registered push notification recipient",
"details":{
"error": "DeviceNotRegistered"
}
}
]
}
(you may ignore the "error": "DeviceNotRegistered" inside this json cos it's expected because I have put an invalid xxxxx input value when calling the api. Even putting a valid input value the result is still returning to the catch block with empty error)
I'm expecting it to return to the then block cos the server actually response with 200 with well formatted json result.
Have I done something wrong so that the call returns to the catch block? Cos the error is empty I have no idea what went wrong.
===============================
after jfriend's reminder I changed to directly disply the error.
console.log("expo replied with error: " + error);
it is show like this now:
Promise { <pending> }
expo replied with error: TypeError: Converting circular structure to JSON
--> starting at object with constructor 'ClientRequest'
| property 'socket' -> object with constructor 'TLSSocket'
--- property '_httpMessage' closes the circle
Anyone can let me know what exactly it means and guide me how to correct my usage?
(problem resolved). the response (responseExpo in the question) is neither a plain data JSON nor a plain string. it is an object with (see github.com/axios/axios#response-schema) some attributes. The real response content is inside "response.data". I was wrongly treating the response to be a plain json object or the http response content.
I had a similar problem and as solution, I used HttpService from nestjs which returns Observable<AxiosResponse<T>>. I fixed the problem by piping and plucking the request like this:
http.put<T>(url, data, config).pipe(pluck('data'))
I had a similar problem with HttpService from nestjs which returns Observable<AxiosResponse<any>>. I resolve with:
this.httpService.post(this.legacyAccessTokenEndpoint, form, { headers: form.getHeaders() }).pipe(map(x => x?.data))
I'm trying to create a lambda authorizer on aws using node.js async/await instead of callbacks but there is no information on how to create the HTTP response returned to API Gateway. For example, if i return this :
{
statusCode: 401
}
the API gateway doesn't seem to understand and return an error 403 to the client :
{
"statusCode": 403,
"error": "Forbidden",
"message": "No principalId set on the Response"
}
Does anyone knows how to do what is described here : https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
but using async / await ?
Thanks in advance !
EDIT :
The way to return an error 401 is simply to throw an error like this :
throw new Error("Unauthorized")
And if the user is explicitly deny / allow, simply return the JSON policy.
To return a 401 error you simply need to throw an error with "Unauthorized" as message, like this :
throw new Error("Unauthorized")
And if the user is explicitly deny / allow, simply return the JSON policy like you would do with callbacks.
I think the accepted solution does not work (anymore). I tried it like this:
exports.authorize = async (event, context) => {
throw new Error("Unauthorized")
}
It works but in my logs I can see this error:
ERROR Invoke Error {"errorType":"Error","errorMessage":"Unauthorized","stack":["Error: Unauthorized"," at Runtime.exports.authorize [as handler] (/var/task/handler/auth.js:21:13)"," at processTicksAndRejections (internal/process/task_queues.js:97:5)"]}
From what I've read (some code samples would be helpful) it sounds like you're not calling the callback right or it's not called in the right place. You can use
callback("Some error message.");
to send back a response w/ a 401 status code. You can also change this by doing something like:
var response = {
statusCode: 401, /* some number */
body: "Oops!" /* some message */
};
callback(null, response);
I would check out this page for more information.
So I have a pretty simple helper function to send errors in my response. I use this function all over my codebase:
exports.error = function (err, res) {
res.send({
success: false,
errorMsg: err.message,
errors: err.errors == null ? [] : err.errors
});
};
I decided to add a status code to it:
exports.error = function (err, res, status) {
res.status(status).send({
success: false,
errorMsg: err.message,
errors: err.errors == null ? [] : err.errors
});
};
If the status is 200 I get the body exactly like the object passed to the send method. The problem is that if status is different from 200 (400 or 500 for example) my response body changes to:
{
config: Object
data: Object
headers: function (d)
status: 500
statusText: "Internal Server Error"
}
And my original response body (the one with success, errorMsg and errors fields) is inside this new response under the data attribute. I have no idea why this is happening but as far as I know I don't have any other custom error handlers in my application. I don't want this behavior and instead I want only my original response body.
I am using the body-parser package, but I believe that it only affects the requests, not the responses.
The response object that you're getting is Angular's response object (see the documentation):
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
AFAIK, when Angular receives a successful HTTP response (like a 200), it will run any of the default transformations to convert the response to, say, a JS object (from a JSON response).
However, it won't do that when the HTTP response indicates an error. In that case, you will get the above-mentioned response object back.
Thanks to #robertklep I found out that the problem was actually in my Angular code that handled errors. Instead of returning the response body my Angular error handler was returning the error itself.