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));
}
}
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));
}
}
Share
Improve this question
edited Jun 14, 2019 at 13:18
Aluan Haddad
31.9k10 gold badges83 silver badges95 bronze badges
asked Jun 6, 2019 at 8:46
jProg2015jProg2015
1,12811 silver badges44 bronze badges
2
- might you be encountering a similar issue to the one outlined in this issue post?: github./expressjs/express/issues/3855 – dusthaines Commented Jun 14, 2019 at 13:20
-
1
FWIW i also get this error if I mistype the name of a function and pass an empty value instead to the router, e.g.
app.get('/api/route/:param', undefined)
– prototype Commented Jul 12, 2021 at 2:08
2 Answers
Reset to default 6 +50This 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));
}
}
This problem happened to me and took me hours and extra support to resolve. My advice is to read the pilation error well, because it should tell you where in your codebase the error is caused.
In my case it was caused by
server.post(`/url/path/to/page`, myMiddleware(), MyClass.myNonExistentFunction);
The reference to a non-existent function had crept into my codebase when during a plicated merge.
Part of the problem with this pilation error is that it doesn't name the undefined callback - in this case 'MyClass.myNonExistentFunction'.