Pradip
Pradip

Reputation: 639

Nest JS TypeORM Error Cannot set headers after they are sent to the client

I have a small Nest JS application where I am trying to develop a GET Rest API.

My Entity looks like:


import { Column, Entity, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm";

@Entity({name: 'workingEnvs'})
export class WorkingEnvironment {
    @PrimaryColumn({ 
        name: 'id',
        type: 'varchar',
        length: 32,
        default: "defaultId",
      }) id: string;

    @Column({
        name: 'name',
        type: 'varchar',
        length: 32,
        default: "workingEnv-420", 
    }) name: string;

    @Column({        
        name: 'something',
        type: 'varchar',
        length: 32,
        default: "practice",
    }) something: string;   

    @Column({ default: true}) isAvailable: boolean;
}

My relevant portion controller looks like (the route):

    @Get()
    async getCollection(@Res() response) {
        const wes = await this.weService.findAll();
        return response.status(HttpStatus.OK).json({
            wes,
        });
    }

And my service code looks like:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from "typeorm";
import { WorkingEnvironment } from './workingenv.entity';

@Injectable()
export class WorkingEnvService { 
    constructor(
        @InjectRepository(WorkingEnvironment)
        private weRepository: Repository<WorkingEnvironment>
    ) {}

    // GET collection service
    async findAll(): Promise<WorkingEnvironment[]> {
        return await this.weRepository.find();
    }
}

When I am calling the REST API with GET:

The data I am getting (correct as I don't have any data):

{"wes":[]}

But my node Js app is crashing with this error:

node:internal/errors:463
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:370:5)
    at ServerResponse.setHeader (node:_http_outgoing:573:11)
    at ServerResponse.header (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\express\lib\response.js:771:10)
    at ServerResponse.send (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\express\lib\response.js:267:15)
    at ExpressAdapter.reply (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\@nestjs\platform-express\adapters\express-adapter.js:24:57)
    at ExceptionsHandler.handleUnknownError (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\@nestjs\core\exceptions\base-exception-filter.js:33:24)
    at ExceptionsHandler.catch (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\@nestjs\core\exceptions\base-exception-filter.js:17:25)
    at ExceptionsHandler.next (C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\@nestjs\core\exceptions\exceptions-handler.js:16:20)
    at C:\Users\pradipm\clients\CloudManager\cm_2\occm\service-infra\nest-services\node_modules\@nestjs\core\router\router-proxy.js:13:35 {
  code: 'ERR_HTTP_HEADERS_SENT'
}

What I am missing here?


Further information:

This is how my app.module.ts looks like (relevant portion):

  TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3307,
    username: 'root',
    password: 'root',
    database: 'workingenv',
    entities: [WorkingEnvironment],
  }),
  WorkingEnvModule,
 ],
  controllers: [PortableController],
  providers: [PortableService, {
    provide: APP_INTERCEPTOR,
    useClass: LoggingInterceptor,
}],

And here is the APP_INTERCEPTOR:

import { constants, utils } from "@app/common";
import { CallHandler, ExecutionContext, HttpException, Injectable, NestInterceptor } from "@nestjs/common";
import { Observable } from "rxjs";
import { catchError, tap } from 'rxjs/operators';
import { LoggerService } from "./logger.service";
const _ = require('lodash')
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
    constructor(private logger: LoggerService) { }
    
    now() {
        const ts = process.hrtime()
        return (ts[0] * 1e3) + (ts[1] / 1e6)
    }

    log(response: any, context: ExecutionContext, startTime: number, isError: Boolean = false) {
        const req = context.switchToHttp().getRequest();
        const { method, url, body } = req;
        let statusCode = context.switchToHttp().getResponse().statusCode

        if(isError && response instanceof HttpException) {
            statusCode = response.getStatus();
        }
        const endTime = this.now()
        if(!_.includes(url, 'health')) {
          const requestId = req.headers[constants.requestIdHeaderName]
          this.logger.access(
            `\t${requestId}\t${statusCode}\t${method}\t${url}\t${endTime - startTime}\t${req.user?.sub}\t${JSON.stringify(utils.scrub(body))}\t${JSON.stringify(utils.scrub(response))}`,
        );
        }
    }

    public intercept(context: ExecutionContext, call$: CallHandler): Observable<unknown> {
        const startTime = this.now()
        return call$.handle().pipe(
            tap({
              next: (val: unknown): void => {
                this.log(val, context, startTime);
              },
              error: (err: Error): void => {
                
                this.log(err, context, startTime, true);
              },
            }),
            catchError(err => {
                throw err
            })
          );
    }
}

Upvotes: 1

Views: 1579

Answers (1)

Num
Num

Reputation: 190

just return your services response:

return this.weService.findAll();

or remove return

response.status(HttpStatus.OK).json(JSON.stringify(wes));

Upvotes: 2

Related Questions