0

I created a filter system API typescript express node mongoose, and there is an error in my code (Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client), is there anyone who will be able to help me, attached the controller code, utils and the error. Thank you.

Utils.ts

class sortPageUtils {
    constructor() { }

    paginateArray(array: any, perPage: any, page: any) {
        return array.slice((page - 1) * perPage, page * perPage)
    }

    sortCompare(key: any) {
        return (a: any, b: any) => {
            const fieldA = a[key]
            const fieldB = b[key]

            let comparison = 0
            if (fieldA > fieldB) {
                comparison = 1
            } else if (fieldA < fieldB) {
                comparison = -1
            }
            return comparison
        }
    }
}

const sort_Page = new sortPageUtils()

export default sort_Page

Controller.ts

GetAllUsers = (req: Request, res: Response, query: any) => {
        Users.find(query || {})
            .then(user => {
                // search and pagination with params config
                const {
                    q = '',
                    perPage = 10,
                    page = 1,
                    sortBy = '_id',
                    sortDesc = false,
                } = req.query;

                const queryLowered = q.toLowerCase()
                const filteredData = user.filter(item => {
                    item.nom.toLowerCase().includes(queryLowered) || item.prenom.toLowerCase().includes(queryLowered) || item.telephone.toLowerCase().includes(queryLowered) || item.email.toLowerCase().includes(queryLowered) || item.role.toLowerCase().includes(queryLowered)
                })

                const sortedData = filteredData.sort(sort_Page.sortCompare(sortBy))
                if (sortDesc) sortedData.reverse()
                res.setHeader('Content-Type', 'application/json');
                res.status(200).json({
                    users: sort_Page.paginateArray(sortedData, perPage, page),
                    total: filteredData.length,
                })
                res.end();

            })
            .catch(err => {
                res.setHeader('Content-Type', 'application/json');
                res.json({ succ1ess: false, message: err });
                res.end();

            });
    }

Error error

Update model.ts

import mongoose from "mongoose"
import bcrypt from "bcryptjs"
import { array } from "@hapi/joi"


const shema: any = mongoose.Schema

export interface IUser extends mongoose.Document {
    nom: string;
    prenom: string;
    fullname: string;
    telephone: string;
    genre: string;
    date_naissance: string;
    email: string;
    password: string;
    role: string;
    ability: string;
    isActive: boolean;
    encryptPassword(password: string): Promise<string>;
    validatePassword(password: string): Promise<boolean>;
}

const usersShema = new shema({
    nom: {
        type: String,
        required: true,
    },
    prenom: {
        type: String,
        required: true,
    },
    telephone: {
        type: String,
        required: true,
        unique: true,
        sparse: true,
    },
    genre: {
        type: String,
        required: true,
        enum: ['homme', 'femme']
    },
    date_naissance: {
        type: Date,
        required: false
    },
    email: {
        type: String,
        required: false,
        unique: true,
        sparse: true,
    },
    password: {
        type: String,
        required: true,
        min: [6, 'Le mot de passe doit contenir au moins 6 caractères'],
    },
    role: {
        type: String,
        required: true,
        enum: ['superadmin', 'admin', 'comptable', 'logistique', 'encadreur']
    },
    ability: {
        type: Array,
        required: true,
    },
    isActive: {
        type: Boolean,
        required: true,
        default: true
    }
}, { _id: true, timestamps: true })


usersShema.methods.encryptPassword = async (password: string): Promise<string> => {
    const salt = await bcrypt.genSalt(10)
    return bcrypt.hash(password, salt)
}
usersShema.methods.validatePassword = async function (password: string): Promise<Boolean> {
    return await bcrypt.compare(password, this.password)
}

const Users = mongoose.model<IUser>('User', usersShema)

export default Users

route.ts

import { Router } from 'express';
import userController from '../controller/UsersAuth.Controller';
import validationToken from '../libs/verifyToken'

class usersRouter {

    router: Router;

    constructor() {
        this.router = Router();
        this.routes();
    }

    routes() {

        this.router.post('/add', userController.AddUser) //Create
        this.router.post('/login', userController.Login) //Route login
        this.router.get('/profile', validationToken.TokenValidation, userController.profile) //Route profile
        this.router.get('/userEmail/:email', userController.GetUser)
        this.router.get('/list', userController.GetAllUsers)

    }
}

export default new usersRouter().router;

call route

this.app.use("/api/auth", usersRouter)

1 Answers1

0

From the error message, it seems that you are setting the headers after part of the body has been written (explained here: Error: Can't set headers after they are sent to the client).

It would think that the error arises in the catch block, where you call res.setHeader. Try to comment out that line and see if the error still occurs.

jamomani
  • 903
  • 1
  • 7
  • 19
  • Thank you for your answer, I have already tried to follow this link but nothing changes, I have already added "return" but nothing changes. Hope to have a new answer from you, thank you – Kiama Cebrail Feb 21 '22 at 05:04
  • It is hard to say where is the problem by looking at this code. You should try to find out which line in your application causes the error. It could be also outside the code you pasted here. It could be that the response is being handled at the same time in the GetAllUsers controller and outside of it. You could start by commenting out the setHeader parts one at the time and see which one was giving rise to the error, or you could debug your code with for example VS code. – jamomani Feb 21 '22 at 06:06
  • I had a look at the stack trace and updated my answer accordingly. Hope it helps fixing the problem. – jamomani Feb 21 '22 at 07:10
  • The error is in the .catch except that when I delete the .catch it is in the status(200), and i did what you said but nothing changes, and in my case I only use that in GetAllUsers only in this controller and I commented the setHeader but nothing changes. I always thank you for your help. – Kiama Cebrail Feb 21 '22 at 15:52
  • The status(200).json itself sets the content-type header, so I guess this is why the error shows there once you have removed the other setHeader in your controller. Anyway, to me it looks like the problem is not in the GetAllUsers controller, but outside of it, where the response is being handled and written even if it has been passed to the controller. This is the core problem I think, but since you have not shared the code outside the controller, it is not possible to exactly say what is the problem. – jamomani Feb 21 '22 at 16:21
  • Thank you for always wanting to help me, I already checked what you told me to do but nothing changes. And there I updated the topic and I added all the codes in this feature. thanks thanks – Kiama Cebrail Feb 21 '22 at 19:03
  • I invite you to see all the codes on this repository : https://github.com/Andryrasolofomanana/expressTsBack I don't know how to thank you for your help. Thank you – Kiama Cebrail Feb 21 '22 at 20:15
  • I see from the repo that now you have removed res.end() here https://github.com/Andryrasolofomanana/expressTsBack/blob/a95fa3cd365e99e97e4d8598422330c41d43abc0/src/controller/UsersAuth.Controller.ts#L133 and in the catch block. Try putting it back. – jamomani Feb 21 '22 at 20:38
  • And in the catch block I would use just something like res.status(500).end(), instead of using .json(), because .json() tries to set the header. – jamomani Feb 21 '22 at 20:58
  • Thank you very much, now the console is clean but there is a problem in my code that I do not know what is blocking the functionality of pagination, search and sorting if you are still kind enough to help me thanks – Kiama Cebrail Feb 22 '22 at 04:00
  • I did console.log(err) in the catch and the same problem in the res.status(200) and when I run it in postman sometimes it's error and sometimes it's 200 with a return [] and 0 – Kiama Cebrail Feb 22 '22 at 04:23
  • And there sometimes it works and sometimes not, Sometimes the error persists. Thank you very much – Kiama Cebrail Feb 22 '22 at 09:36
  • It looks like you are still missing the res.end() after res.status(200).json({...}), I think you should add res.end() in there like on line 135 in UsersAuth.Controller.ts. Check after that what kind of error do you get, is it still the header error or something else, and what is the status code. – jamomani Feb 22 '22 at 09:57
  • There I have already added some but out of 4 send on postman only 1 responds well. Thank you – Kiama Cebrail Feb 22 '22 at 10:07
  • What do you mean only one responds well? What error message do you get? Do you still get the "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client Api express ts" error? – jamomani Feb 22 '22 at 10:17
  • I insist on having the response but the error in the console is always the same " Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client " – Kiama Cebrail Feb 22 '22 at 10:41
  • attached a screenshot thank you https://www.awesomescreenshot.com/video/7528610?key=4ba59dad1bbc2497eb6538fac91a89ae – Kiama Cebrail Feb 22 '22 at 10:48
  • If you change the .json() part with send(”hello”), do you get the ”hello” text in postman and the headers error in the console? – jamomani Feb 22 '22 at 11:33
  • Thank you very much for your help, it's solved by your help, I tried to send res.send('hello') and I commented all the codes in "then" but it's the same problem , I removed the params query and it worked I concluded that this is the problem because I declared it as an typed any, so I declared it as an empty variable and it worked `let query; Users.find(query || {})` – Kiama Cebrail Feb 22 '22 at 12:54