I am trying to access data from the rest API I created however the routes are not displaying any JSON data. I have server, controller and data controller classes that I am using to initialize and configure the API. The server loads correctly along with both of the controllers, but when I go to an endpoint it just shows the default React app page.
Server load controller method:
public loadControllers(controllers: Array<Controller>): void {
controllers.forEach(controller => {
console.log(controller, controller.path)
this.app.use(controller.path, controller.setRoutes());
});
};
Controller set routes method:
public setRoutes = (): Router => {
for (const route of this.routes) {
for (const mw of route.localMiddleware) {
this.router.use(route.path, mw)
};
switch (route.method) {
case Methods.GET:
this.router.get(route.path, route.handler);
break;
case Methods.POST:
this.router.post(route.path, route.handler);
break;
case Methods.PUT:
this.router.put(route.path, route.handler);
break;
case Methods.DELETE:
this.router.delete(route.path, route.handler);
break;
default:
console.log('not a valid method')
break;
};
};
return this.router;
}
DataController example route and handler:
routes = [
{
path: '/locations',
method: Methods.GET,
handler: this.handleGetLocations,
localMiddleware: [],
},
]
async handleGetLocations (req: Request, res: Response, next: NextFunction, id?: number) {
try{
this.dbConn.initConnectionPool()
.then((pool) => {
pool.query(`query here`)
})
.then((data) => {
res.send(data);
})
}
catch(err){
console.log(err);
}
}
When I console log the routes or any of the functions they all show up correctly.
CodePudding user response:
For starters, you have problems with this
handling. When you do something like this:
this.router.get(route.path, route.handler);
and router.handler
points to a function such as your handleGetLocations()
which expects to use this
and expects it to be your object, the value of this
won't have the right value. You either need to .bind()
this
to your function or you need to properly use arrow
functions to retain the proper value of this
.
When the value of this
is wrong, then something like this.dbConn.initConnectionPool()
in your
handleGetLocations()function will fail because
this` is not the correct value.
You aren't showing enough overall context in the code in your question for us to understand what this
is supposed to point to and therefore how to properly declare or structure things to fix the problem.
It is possible, you could change this code:
routes = [
{
path: '/locations',
method: Methods.GET,
handler: this.handleGetLocations,
localMiddleware: [],
},
]
to this:
routes = [
{
path: '/locations',
method: Methods.GET,
handler: this.handleGetLocations.bind(this),
localMiddleware: [],
},
]
But, that would only work if this
had the proper value in that array declaration which we don't have enough code context to really know.
There are other problems in your code too such as no proper error handling in handleGetLocations()
. If this.dbConn.initConnectionPool()
rejects, you don't have a handler for it. You either need to await
it so that your try/catch
will catch the rejection or you need a .catch()
after the .then()
to catch the rejection.
FYI, adding your own framework on top of another framework just seems needlessly complicated here. You've obscured the very simple declaration of routes in Express with your own system that introduces new problems and doesn't really make anything clearer and is also a system that nobody else is familiar with.
Oh, one more thing. This code:
async handleGetLocations(req: Request, res: Response, next: NextFunction, id ? : number) {
try {
await this.dbConn.initConnectionPool()
.then((pool) => {
pool.query(`query here`)
})
.then((data) => {
res.send(data);
})
} catch (err) {
console.log(err);
}
}
Needs to fix several things. As said above, you have to fix how this
is passed to this function. Then, you have to fix error handling to actually capture a rejected promise from either of the asynchronous calls here. Then, you have to actually capture the result of the pool.query()
so you can do something with it. You were ignoring it.
Then, you have to actually send an error response if a promise rejects.
async handleGetLocations(req: Request, res: Response, next: NextFunction, id ? : number) {
try {
const pool = await this.dbConn.initConnectionPool();
const data = await pool.query(`query here`);
res.send(data);
} catch (err) {
console.log(err);
res.sendStatus(500);
}
}
Whether there are other problems in your framework on top of a framework is impossible for us to tell with this amount of code. Stepping through a simple test app with one GET route in it should be able to determine if you end up configuring the proper Express route and whether that route handler ever gets called. Since we don't have a reproducible, runnable set of code here that's not something we can do. As I said above, I'm not a fan of putting your own framework on top of an existing framework because it just seems like an added level of complexity without significant benefit. And, you have to properly debug (since it doesn't yet work) and maintain your framework now too.