where to should write res.send() in node.js app

Issue

In my app I have a category collection that saves the category title with its image ID. The image is saved in another collection with its meta data like path , type and so on. So for retrieving category I should retrieve category image in image collection by its ID and add image path to category object that is retrieved from category collection and send it to client…But I don’t know where should I send categories to client?
When I send the response face this error :

 throw er; // Unhandled 'error' event
      ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:561:11)
    at ServerResponse.header (H:\node.js\online-store\app\node_modules\express\lib\response.js:771:10)
    at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (H:\node.js\online-store\app\node_modules\express\lib\response.js:267:15)
    at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:158:21)
    at H:\node.js\online-store\app\controllers\pcategory.controller.js:123:19
    at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4845:18
    at processTicksAndRejections (internal/process/task_queues.js:77:11)
Emitted 'error' event on Function instance at:
    at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4847:15
    at processTicksAndRejections (internal/process/task_queues.js:77:11) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

This is my code :

exports.getAll = async (req, res) => {
     try{
           
        const categories = await ProductCategory.find({});
   
            categories.map(async(category)=>{
             
           await File.findById(category.imageID).exec(function(err,file){
                if(err){
                    console.log(err)
                
                    
                }else if(file) {
                                            
                   category.imagePath = file.file_path;
                   tempCategories.push(category)
                                
                  
               }
                 res.send(tempCategories);
                        
            })
           
           })
         
         
           return res.send(tempCategories); 
            
    }catch {
        res.json(err =>{
            console.log(err);
            res.status(500).send({
                message:
                  err.message || "There is an error in retrieving category"
              });

    })

    }
   
}

Solution

The problem is that nothing in your code is waiting for the asynchronous operations you’re doing in your map callback to complete, so it does the res.send at the end right away — and then does res.send again within the map callback later when the async operations complete. Instead, wait for them to finish and send the result.

Also, you’re using res.send where I suspect you want res.json, and using res.json later incorrectly (it doesn’t take a callback).

See comments:

exports.getAll = async (req, res) => {
    try {
        // Get the categories
        const categories = await ProductCategory.find({});
        // Get the files for the categories, wait for the result
        const result = await Promise.all(categories.map(async (category) => {
            const file = await File.findById(category.imageID).exec();
            // You probably can't modify the `category` object, so let's create
            // and return a new object
            return {...category, imagePath: file.file_path};
        }));
        // Send the result converted to JSON
        return res.json(tempCategories);
    } catch (err) { // Accept the error
        // Send an error response
        res.status(500).json({
            message: err.message || "There is an error in retrieving category"
        });
    }
};

Side note: Your original code was using map without using the array it creates. That’s an antipattern (sadly it seems to be one someone somewhere is teaching). I wrote up why and what to do instead here. (In my update to your code, I still use map, but I use the array it creates, passing it to Promise.all so we can wait for all those promises to settle.)

Answered By – T.J. Crowder

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published