Frastio Agustian
Frastio Agustian

Reputation: 95

express app not giving any response but the data is saved to mongodb. ERR_HTTP_HEADERS_SENT

I am still learning about the MERN stack, and I am making a simple CRUD app using the MERN stack. I added some validators using express-validator for the requests. The problem is, somehow the data is sent and saved to the database but not giving any response when I try it using Postman.

I think the problem is either on the response of the post controller function or the validators. I got no idea where is it exactly though. I've been stuck here for like an hour. Already going back and forth to get some answers on google. but couldnt find any. here are the codes.

index.js :

import express from 'express'
import mongoose from 'mongoose'
import dotenv from 'dotenv'

import { router as postRoutes } from './routes/post.js'
import { router as authRoutes } from './routes/auth.js'

//setup
const app = express()
app.use(express.json());
dotenv.config();

app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin','*')
    res.setHeader('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
    next();
})

//route groups
app.use('/v1/post', postRoutes)
app.use('/v1/auth', authRoutes)

//validation
app.use((error,req,res,next) => {
    const status = error.errStatus || 500
    const message = error.message
    const data = error.data
    res.status(status).json({message : message, data: data})
})

//connect to mongodb
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(app.listen(4000, ()=>{ console.log('Server is up!')}))
.catch(err => console.log(err))

Post controller : *Note: I dont send the whole code of the post controller here, only the create post function

import { validationResult } from 'express-validator'
import PostSchema from '../models/post.js'

//handle post requests
const createPost = (req, res, next) => {
    const title = req.body.title
    const content = req.body.content
    //get errors result from express-validator
    const errors =  validationResult(req)
    if(!errors.isEmpty()){
       const err = new Error('Invalid request')
       err.errStatus = 400
       err.data = errors.array()
       throw err
    }

    const Posts = new PostSchema({
        title: title,
        content: content,
        author: {
            _id: 1,
            name: 'fratio '
        }
    })
    
    Posts.save()
    .then(result =>{
        res.status(201).json({ //the error messsage says there is an error on this line
            description: "successfully created",
            data : result,
        })
    })
    .catch(err =>console.log(err))
    next()
}

export {createPost}

Post routes :

import express from 'express'
import { body } from 'express-validator'
import { createPost, deletePost, getPosts, updatePost } from '../controllers/post.js'

const router = express.Router()

router.get('/', getPosts)
router.post('/create',
    [
        body('title').isLength({min: 5}).withMessage('minimum length is 5 characters'), 
        body('content').isLength({min: 5}).withMessage('minimum length is 5 characters')
    ],  createPost)
router.put('/:id/update', updatePost)
router.delete('/:id/delete', deletePost)

export  { router }

Post Schema :

import mongoose from 'mongoose'

const Schema = mongoose.Schema
const PostSchema = new Schema({
    title: {
        type : String,
        required : true,
    },
    content: {
        type : String,
        required : true
    },
    author: {
        type: Object,
        required: true
    }
},{
    timestamp: true
})

export default  mongoose.model("PostSchema", PostSchema) 

ERROR MESSAGE :

[nodemon] starting `node index.js`
Server is up!
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 (D:\Programming\Web Development\mern-playground\mern-basic-1\server\node_modules\express\lib\response.js:771:10)
    at ServerResponse.send (D:\Programming\Web Development\mern-playground\mern-basic-1\server\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (D:\Programming\Web Development\mern-playground\mern-basic-1\server\node_modules\express\lib\response.js:267:15)
    at file:///D:/Programming/Web%20Development/mern-playground/mern-basic-1/server/controllers/post.js:28:25
    at processTicksAndRejections (internal/process/task_queues.js:95:5) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

Thank you so much. I hope you guys can help me out, I really got no idea how to fix this. Sorry if the code is hard to read.

Upvotes: 1

Views: 52

Answers (1)

Ariel
Ariel

Reputation: 1436

You have a problem with your promise logic.

const createPost = (req, res, next) => {
    
    // This will create a promise, when the promise is resolved "then" will be executed
    // if the promise is rejected, "catch" will be executed.
    // A promise doesn't actually stops the flow of the code here, "next()" will be called
    // before the promise is resolved/rejected
    Posts.save()
    .then(result =>{
        res.status(201).json({ //the error messsage says there is an error on this line
            description: "successfully created",
            data : result,
        })
    })
    .catch(err =>console.log(err));

    // "next" is called right after the promise is created
    // but the promise doesn't stop the flow of the code
    // so this is executed while the promise is still being resolved/reject
    next()
}

You are calling next before the promise is resolved/rejected, so the next handler is probably the default 404 handler of express and that is the response you will receive. Later, the promise will be resolved/rejected and you will try to send a response again and that's why the error is thrown.

The solution is simple, move the next() call inside your promise or delete it.

Upvotes: 1

Related Questions