Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express JS: Cannot read property 'lazyrouter' of undefined

Tags:

I'm creating a layer of abstraction around Express JS and I've encountered a problem. Considering the following code (see bottom), when calling registerRoute and hitting the line:

expressFnc(route, (req: any, res: any, next: any) => dummy(req, res, next));

I am encountering the error:

Cannot read property 'lazyrouter' of undefined

In this context 'this', I assume, applies to ExpressJS (lib/application.js:479:10).

const express = require("express");

export class ExpressHttpHost implements IHttpHost {
  private host: any = express();
  private contentResolver?: ContentResolver;

  public configure(contentResolver: ContentResolver): void {
    this.contentResolver = contentResolver;
  }

  public registerRoute(
    route: string,
    verb: HttpVerb,
    handler: (request: HttpRequest) => HttpResponse,
  ): void {
    switch (verb) {
      case HttpVerb.Get:
        this.createDummyRequest(this.host.get, route, handler);
        break;
      case HttpVerb.Delete:
        this.createDummyRequest(this.host.delete, route, handler);
        break;
      case HttpVerb.Options:
        this.createDummyRequest(this.host.options, route, handler);
        break;
      case HttpVerb.Patch:
        this.createDummyRequest(this.host.patch, route, handler);
        break;
      case HttpVerb.Post:
        this.createDummyRequest(this.host.post, route, handler);
        break;
      case HttpVerb.Put:
        this.createDummyRequest(this.host.put, route, handler);
        break;
      case HttpVerb.All:
        this.createDummyRequest(this.host.get, route, handler);
        this.createDummyRequest(this.host.delete, route, handler);
        this.createDummyRequest(this.host.options, route, handler);
        this.createDummyRequest(this.host.patch, route, handler);
        this.createDummyRequest(this.host.post, route, handler);
        this.createDummyRequest(this.host.put, route, handler);
        break;
      default:
        throw new Error("Verb is not supported.");
    }
  }

  public start(options: IHttpHostOptions): void {
    this.host.listen(options.port ? options.port : 80);
  }

  private createHttpRequest(expressReq: any): HttpRequest {
    return new HttpRequest(
      expressReq.headers,
      expressReq.params,
      expressReq.body,
    );
  }

  private createDummyRequest(expressFnc: any, route: string, handler: (request: HttpRequest) => HttpResponse): void {
    const dummy = (expressReq: any, expressRes: any, next: any) => {
      const httpRequest = this.createHttpRequest(expressReq);

      const response = handler(httpRequest);
      const responseStatus = response.status();
      const responseMimeType = response.mimeType();
      const responseContent = response.content(this.contentResolver);

      expressRes.set("Content-Type", responseMimeType);
      expressRes.status(responseStatus);
      expressRes.send(responseContent);
      next();
    };
    expressFnc(route, (req: any, res: any, next: any) => dummy(req, res, next));
  }
}
like image 837
jProg2015 Avatar asked Jun 06 '19 08:06

jProg2015


1 Answers

This might happen because express functions when passed as arguments loose reference to the host object. Try manually binding them back. See the bindings below in the switch:

const express = require("express");

export class ExpressHttpHost implements IHttpHost {
  private host: any = express();
  private contentResolver?: ContentResolver;

  public configure(contentResolver: ContentResolver): void {
    this.contentResolver = contentResolver;
  }

  public registerRoute(
    route: string,
    verb: HttpVerb,
    handler: (request: HttpRequest) => HttpResponse,
  ): void {
    switch (verb) {
      case HttpVerb.Get:
        this.createDummyRequest(this.host.get.bind(this.host), route, handler);
        break;
      case HttpVerb.Delete:
        this.createDummyRequest(this.host.delete.bind(this.host), route, handler);
        break;
      case HttpVerb.Options:
        this.createDummyRequest(this.host.options.bind(this.host), route, handler);
        break;
      case HttpVerb.Patch:
        this.createDummyRequest(this.host.patch.bind(this.host), route, handler);
        break;
      case HttpVerb.Post:
        this.createDummyRequest(this.host.post.bind(this.host), route, handler);
        break;
      case HttpVerb.Put:
        this.createDummyRequest(this.host.put.bind(this.host), route, handler);
        break;
      case HttpVerb.All:
        this.createDummyRequest(this.host.get.bind(this.host), route, handler);
        this.createDummyRequest(this.host.delete.bind(this.host), route, handler);
        this.createDummyRequest(this.host.options.bind(this.host), route, handler);
        this.createDummyRequest(this.host.patch.bind(this.host), route, handler);
        this.createDummyRequest(this.host.post.bind(this.host), route, handler);
        this.createDummyRequest(this.host.put.bind(this.host), route, handler);
        break;
      default:
        throw new Error("Verb is not supported.");
    }
  }

  public start(options: IHttpHostOptions): void {
    this.host.listen(options.port ? options.port : 80);
  }

  private createHttpRequest(expressReq: any): HttpRequest {
    return new HttpRequest(
      expressReq.headers,
      expressReq.params,
      expressReq.body,
    );
  }

  private createDummyRequest(expressFnc: any, route: string, handler: (request: HttpRequest) => HttpResponse): void {
    const dummy = (expressReq: any, expressRes: any, next: any) => {
      const httpRequest = this.createHttpRequest(expressReq);

      const response = handler(httpRequest);
      const responseStatus = response.status();
      const responseMimeType = response.mimeType();
      const responseContent = response.content(this.contentResolver);

      expressRes.set("Content-Type", responseMimeType);
      expressRes.status(responseStatus);
      expressRes.send(responseContent);
      next();
    };
    expressFnc(route, (req: any, res: any, next: any) => dummy(req, res, next));
  }
}
like image 165
Gleb Kostyunin Avatar answered Oct 21 '22 03:10

Gleb Kostyunin