Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The error middleware throws unhandler error for first container config and last router #1539

Open
ajoshi31 opened this issue Oct 6, 2023 · 1 comment

Comments

@ajoshi31
Copy link

ajoshi31 commented Oct 6, 2023

Expected Behavior

The unhandler error captures should pass through the error middleware and should send the proper error message. All route should behave same using by passing error to error middleware

Current Behavior

For any first container config that is imported and its last router is giving this error:

Error: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:405:5)
    at ServerResponse.setHeader (node:_http_outgoing:648:11)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at runNextTicks (node:internal/process/task_queues:64:3)
    at processImmediate (node:internal/timers:447:9)

Possible Solution

NA

Steps to Reproduce (for bugs)

controller.ts

import { Request, Response, NextFunction } from 'express';
import { injectable } from 'inversify';
import { BaseController } from '@sn/server';
import { AppError } from '@sn/core';
import { logDecorator } from '@sn/shared';

@injectable()
export class GetMetaController extends BaseController {
  constructor() {
    super();
  }

  @logDecorator()
  public async executeImpl(
    request: Request,
    response: Response,
    next: NextFunction
  ): Promise<any> {
    try {
      throw new Error('Throw some error');
      // return this.ok<any>(response, { user: 1 });
    } catch (err: any) {
      return this.fail(response, new AppError.UnexpectedError(err), next);
    }
  }
}

route.ts

import { NextFunction, Request, Response } from 'express';
import { inject } from 'inversify';
import { controller, httpGet } from 'inversify-express-utils';
import { ApiPath } from 'swagger-express-ts';
import TYPES from '@ioc/constant/Types';
import { GetRefVersionController } from '../controller/GetRefVersionController';
import { GetMetaController } from '../controller/GetMetaController';

@ApiPath({
  name: 'RefVersions',
  path: '/refVersion'
})
@controller('/refVersion')
export abstract class RefVersionRouters {
  constructor(
    @inject(TYPES.GetRefVersionController)
    private readonly _getRefVersionController: GetRefVersionController,

    @inject(TYPES.GetMetaController)
    private readonly _getMeta: GetMetaController
  ) {}

  @httpGet('/version')
  public async getAllRefVersion(
    request: Request,
    response: Response,
    next: NextFunction
  ) {
    return this._getRefVersionController.execute(request, response, next);
  }

  @httpGet('/meta')
  public async getMeta(
    request: Request,
    response: Response,
    next: NextFunction
  ) {
    return this._getMeta.execute(request, response, next);
  }
}

module_config.ts

import { AsyncContainerModule, interfaces } from 'inversify';

import { errorHandler } from '@core/error/ErrorHandler';
import TYPES from '@ioc/constant/Types';

import { RefVersionRouters } from './infrastructure/routers/RefVersionRouter';

import { GetRefVersionController } from './infrastructure/controller/GetRefVersionController';
import { GetMetaController } from './infrastructure/controller/GetMetaController';

const SystemConfigContainer = new AsyncContainerModule(
  async (bind: interfaces.Bind) => {
    try {
      RefVersionRouters;

      bind<GetRefVersionController>(TYPES.GetRefVersionController)
        .to(GetRefVersionController)
        .inRequestScope();
      bind<GetMetaController>(TYPES.GetMetaController)
        .to(GetMetaController)
        .inRequestScope();
    } catch (err: unknown) {
      errorHandler.handleError('SystemIOC Error', err as Error);
    }
  }
);

export { SystemConfigContainer };

Ioc_config.ts

import { Container } from 'inversify';

import { errorHandler } from '@core/error/ErrorHandler';
import TYPES from './constant/Types';
import { SystemConfigContainer } from '@system-module/SystemIocConfig';
import { CheckConfigContainer } from '../module/check/CheckConfig';
import { UserConfigContainer } from '@user-module/UserIocConfig';

const InversifyConfigContainer = async () => {
  const container = new Container();

  try {
    container.loadAsync(SystemConfigContainer);
    container.loadAsync(UserConfigContainer);
    container.loadAsync(CheckConfigContainer);
  } catch (err: unknown) {
    errorHandler.handleError('IOC Error', err as Error);
  }

  return container;
};

export { InversifyConfigContainer };

AppServer.ts

import 'reflect-metadata';
/* eslint-disable  @typescript-eslint/no-explicit-any */
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('source-map-support').install();
import * as dotenv from 'dotenv';
import { InversifyExpressServer } from 'inversify-express-utils';
import { ExpressMiddleware, errorMiddleware } from './../middleware';
import { logger } from '@sn/shared';
// import { envConfig } from './config';
// import { ExitProcess } from './core/utils/ExitProcess';

dotenv.config();
const port = process.env.PORT || 3000;

export const appServer = async (config: any): Promise<void> => {
  try {
    const server = new InversifyExpressServer(config, null, {
      rootPath: '/api/v1'
    });

    /* Adding middleware to express server */
    server.setConfig((app) => {
      new ExpressMiddleware(app);
    });

    server.setErrorConfig(errorMiddleware);
    const serverInstance = server.build();

    serverInstance.listen(port, () => {
      logger.info(`Server running at http://127.0.0.1:${port}/`);
    });

    // ExitProcess(server);
  } catch (err) {
    logger.error('Error in SERVER', err);
  }
};

MainAppServer.ts:

import 'module-alias/register';
import 'reflect-metadata';
import { InversifyConfigContainer } from '@ioc/IocConfig';

import sourceMapSupport from 'source-map-support';
import { logger } from '@sn/shared';
import { appServer } from '@sn/server';

sourceMapSupport.install();

const expressApp = (async (): Promise<void> => {
  /* Setting up IoC */
  try {
    const containerConfig = await InversifyConfigContainer();
    await appServer(containerConfig);
  } catch (err) {
    logger.error('Error', err);
  }
})();

expressApp;

Context

If import is like this:

import { SystemConfigContainer } from '@system-module/SystemIocConfig';
import { CheckConfigContainer } from '../module/check/CheckConfig';
import { UserConfigContainer } from '@user-module/UserIocConfig';

Here the last route of import { SystemConfigContainer } from '@system-module/SystemIocConfig'; throws the error of request already sent

If we change the import like this

import { CheckConfigContainer } from '../module/check/CheckConfig';
import { SystemConfigContainer } from '@system-module/SystemIocConfig';
import { UserConfigContainer } from '@user-module/UserIocConfig';

Then last route of import { CheckConfigContainer } from '../module/check/CheckConfig'; throws the errror:

All other route works perfectly

Your Environment

  • "inversify": "^6.0.1",
  • "inversify-express-utils": "^6.4.3",
  • nodejs : 18+
    
  • MacOs

Stack trace

Current Behavior

For any first container config that is imported and its last router is giving this error:
Error: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:405:5)
    at ServerResponse.setHeader (node:_http_outgoing:648:11)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at runNextTicks (node:internal/process/task_queues:64:3)
    at processImmediate (node:internal/timers:447:9)
@notaphplover
Copy link
Member

Hey @rsaz, is this related to inversify/inversify-express-utils#255?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

2 participants