Error Object When Fetching From Express Server - javascript

I have an Express server with a simple error handler. All the err object passed to it are Error objects.
const errorHandler = (err, req, res, next) => {
logError(`Express Error Handler: ${err}`);
res.status(500).json(err);
};
I am calling the server's routes using request:
request
.post(
{
uri: url,
timeout,
json: true,
form: {
currentStepUid,
sourceStepUid: previousStepUid,
config,
},
},
(error, response, body) => {
// Handle errors
}
)
});
My problem is that the error are not coming through as error objects, but rather as an error property on the body object.
How should I have Express set up so that I get error objects back?

A 500 status is NOT reported by request.post() as an error. The http server was contacted and a response was supplied. That is not what it considers an error. It is up to your own code to detect that condition from the http response and then treat it as an error in your own code.
You will need to look at the actual response to see the http 500 status code. The error object IS the http response body so that's where it should be. That's where you need to get it from.
If you have to do this same logic in multiple places, you could make your own wrapper function for request.post() that would examine the http status code and if it's in a range that you consider an error, then get the http response body and make that into an error.

Related

Error: Cannot remove headers after they are sent to the client

I was working on admin registration and admin data retrieving react app. The registration works fine but retrieving admin data is crushing my backend. I have encountered this error when call the given endpoint from my react app. But when I call it from Postman it works very fine. And when I see the console on my browser my react app sends two calls simultaneously instead of one. On these calls my app crushes. If any one can show me how to solve this problem?
For backend = Node.js with express.js framework
For frontend = React
This is the error I am getting
node:internal/errors:465
ErrorCaptureStackTrace(err);
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot remove headers after they are sent to the client
at new NodeError (node:internal/errors:372:5)
at ServerResponse.removeHeader (node:_http_outgoing:654:11)
at ServerResponse.send (C:\Users\Momentum\Documents\The Technologies\Madudi-App-Api\node_modules\express\lib\response.js:214:10)
at C:\Users\Momentum\Documents\The Technologies\Madudi-App-Api\api\index.js:22:72
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...
This is how I setup my endpoint and changed the data to a string in order to get simple response but it crushes
const makeHttpRequest = (controller, helper) => {
const makeRequest = (req, res) => {
try {
var data = "Trying response";
res.status(200).send({ status: true, data: data });
} catch (error) {
console.log(`ERROR: ${error.message}`);
res.status(400).send({ status: false, error: error.message });
}
};
return { makeRequest };
};
const makeApi = ({router, controller, helper}) => {
router.get("/test", (req, res) => res.send("Router is Woking..."));
router.get("/admin/get_all_admins", async (req, res) => res.send(await makeHttpRequest(controller, helper).makeRequest(req, res)));
}
module.exports = { makeApi }
And this is the call from my react app
export default function GetAllUsers() {
useEffect(() =>{
try{
const response = axios.get('http://localhost:5000/admin/get_all_admins').then(async (response) => {
console.log('response ', response)
return response.data;
});
}catch(error) {
return [];
}
}, [])
I'm not familiar with this method of responding to requests, but in my own opinion the error you are facing happens when you're sending multiple response.
This may be the asynchronous nature of JavaScript, there by causing another request to be sent after the function is done.
You should also try to return the response, so that once it's done it cancels out of the function. You can use the example below
const handler = (req,res) => {
return res.status(200).json(data)}
This particular error happens when you try to send more than one response for the same incoming request (something you are not allowed to do).
You are calling res.send() more than one for the same request on your server.
The first happens in the makeRequest() function.
The second time happens in this line of code:
router.get("/admin/get_all_admins", async (req, res) => res.send(await makeHttpRequest(controller, helper).makeRequest(req, res)));
You can't do that. You get ONE response per incoming request. So, either send the response in makeRquest() and don't send it in the caller. Or, don't send the response in makeRequest() and just return what the response should be and let the caller send it. Pick one model or the other.
I am not familiar with this way of setting up the server. Looks strange to me. However, in router.get("/admin/get_all_admins" your sending a response which calls a function makeHttpRequest that also sends a response. Thus you get an error Cannot remove headers after they are sent to the client because you're sending a response twice.

Restify is returning 405 instead of 404

We are using restify 6.4.0 and instead of 404 for non-existent endpoints we get 405 (method not allowed).
I have identified the core issue which is this line server.opts('.*', (req, res) => res.send(204));. For some reason, when it is present, the 405 issue is present. When I remove it, then restify starts working as expected (404 for nonexisting endpoints, 405 for existing endpoints with different HTTP Method existing)
This is working example
var restify = require('restify');
const server = restify.createServer({
name: 'myapp',
version: '1.0.0'
});
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser());
server.opts('.*', (req, res) => res.send(204));
server.get('/echo/:name', function (req, res, next) {
res.send(req.params);
return next();
});
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url);
});
When I use postman and call localhost:8080/noo, this is the response
{
"code": "MethodNotAllowed",
"message": "GET is not allowed"
}
However when I remove the server.opts('.*', (req, res) => res.send(204)); line, I got expected result
{
"code": "ResourceNotFound",
"message": "/noo does not exist"
}
Its not clear to me, why this is happening - tried Postman and also another Node.js code to make sure its not caused by some pre-flight request done by Chrome or other browsers. Calling the server with this code:
var request = require('request');
var options = {
'method': 'GET',
'url': 'http://localhost:8080/noo',
'headers': {
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Is getting me this response
{"code":"MethodNotAllowed","message":"GET is not allowed"}
(and same as with postman, when I delete the server.opts... line, I get proper response
{"code":"ResourceNotFound","message":"/noo does not exist"}
Can someone explain whats happening?
The line:
server.opts('.*', (req, res) => res.send(204));
Is a catch all handler to return 204 response for all HTTP OPTONS requests.
Looks like this results in restify always concluding that you do have a handler for a given route (since it is a catch all for every route), just not for the method that is being asked for - i.e. anything but OPTIONS requests.
Hence you get 405 "Method not allowed" rather than 404 "Not found"

How can I get my fetch error to show an http status code?

I have a react component and I'm making a network call to set the state. Eventually I want to pass this down to other child components, but just getting the plumbing to work at the moment.
I'm trying to catch errors correctly when calling out to my backend (an express server in the app). I attempted to force an error by fetching data from an endpoint that doesn't exist. This should throw a 404 since it doesn't exist, right? How can I get that error surfaced in the catch statement? Right now my error is SyntaxError: Unexpected token < in JSON at position 0 at eval (app.js:61)
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
fetch('/api/wrong_endpoint').then((data) => {
return data.json();
}).then((body) => {
this.setState({data: body})
}).catch(err => console.log(err));
}
render() {
console.log('logging the states');
console.log(this.state.data);
return (
<div>
<ContactList />
<ContactDetail />
<AddContactModal />
</div>
);
}
}
I'll try to go step by step
fetch method doesn't throw an error even if you get the 4xx or 5xx response codes. Please read about the Fetch API carefully, I believe you can find a lot of interesting you don't know about it.
You can easily check the response status as follows (please read about the Response object and its methods/properties):
fetch('/api/wrong_endpoint').then((response) => {
console.log('status code', response.status)
})
It's hard to say if your server really returns 404 code because I don't know your express setup. If you set some fallback handler like app.get('*', ...) then it might as well return 200 success code. You can check the response status and its body in devTools of the browser. But I believe it's better if you configure at least your /api router to return 404 error if the requested /api/... route isn't found.
What I'm really sure of is that your server returns some HTML layout in the response. And you try to parse it as JSON string via data.json() and of course you get the syntax error since it's not JSON (html layout starts with < symbol hence the error: SyntaxError: Unexpected token <)
Generally, if you are using the fetch API, errors 40x and 50x will not go into the subsequent blocks, as the promise from fetch only rejects network errors (not HTTP errors or anything else). Therefore, requesting for data from an 'incorrect' endpoint will be handled within the first then block.
I would recommend you to use check your http response body based on the Response.Ok property. Successful responses will be handled within that condition, whereas any other responses (ok: false) will be handled on the other statement.
fetch('/api/wrong_endpoint')
.then(response => {
console.log(response) // full response body
console.log(response.status); // get only the response.status
if (!response.ok) {
// http errors 40x and 50x will go into this statement
// do something to handle it
} else if (response.ok) {
// handles status code 200
}
})
.then(
// ...

Cant access values in my EXPRESS / NodeJs response error [String: 'Error: Request returned error code: 404

i am trying to access values in my express response error. When I console.log the error like this...
app.use(function(err, req, res, next){
console.log(err)
});
The console looks like the following
[String: 'Error: Request returned error code: 404 and body: {"status":404,"title":"No option(s) were found with this query.","type":"https://developer.bigcommerce.com/api#api-status-codes"}']
For Example; how do i access err.title so i can send this to the client.
reference this question for more Parse Error response in Express NodeJS app
If I'm not wrong, express uses a generic error object defined in the standard, and there are only three properties:
Error.prototype.constructor
Specifies the function that created an
instance's prototype.
Error.prototype.message
Error message.
Error.prototype.name
Error name.
Some libraries (like mongoose for example) use a custom error object, so you can access to more error details (and properties), if this is your case, you could try to look for an "Error handling" chapter in the official docs of that library, and see if you have more details in the error object. In this cases I think you won't use the err object provided by express but an err provided by the library method which rises the error, somewhat like:
...
app.use((err, req, res, next)=>{
library.method((err1, data)=>{
console.log(err1);// use this error object
})
})
...

express - catch request failed error

I am using the request module to send requests to a URL
var req = require('request');
when the response is received, I would like to write that file on the node server, so I am piping it to crateWriteStream
req.get(myUrl)
.on('error', function(err) {
console.log('there is an error');
})
.pipe(fs.createWriteStream('userdir/abc.png'));
This works fine if there is no error returned by req.get. In case req.get, fails I would like to not write the file locally and instead do something else.
I introduced .on('error'..) for this but the on('error') code never gets executed and .pipe tries to write the file that does not exist.
How can catch an error returned by req.get() and only write when there is no error.
I think you are using streams but normally you can use the callback to receive the all information and then check if there is any error.
Personally I would do something like:
var req = require('request');
req.get(myUrl, function (error, response, body) {
if (error || response.statusCode != 200) {
console.log(error) // Do something with your error
}
// If no errors, this code will be executed
// Write in file
})

Categories