Routing in express - node.js

I have structure like this:
server.ts
routes/
index.ts
homeRoute.ts
In server.ts:
let app = Express();
app.use(router);
In routes/index.ts:
const routes = Router();
export default function router() {
routes.use('/home', homeRoute);
}
In routes/homeRoutes.ts
let homeRouter = Express.Router();
export default function homeRoute(req: Request, res: Response, next: NextFunction) {
console.log('home route');
homeRouter.get('/home', function);
next();
}
My problem is when i call http://localhost:3000, it run to index.ts file ( I console.log some things so I know that), however it don't execute my routes.use('/home', homeRoute).
I don't know why it is. Please help me fix it.

Understand how import and export works. Ideally your code should be something like this.
server.ts
import * as express from 'express';
import {routes} from './routes';
const app = express();
routes(app);
routes/index.ts
import {homeRoute} from './homeRoutes';
export const routes = (app) => {
homeRoute(app);
}
routes/homeRoutes.ts
export const homeRoute = (app) => {
app.get('/home', function (req, res, next) {
res.render('home');
});
}

Related

How to read all routes dynamically in node.js

I am trying to read all routes in my app.js file from './routes' folder,but
gettingerror:"TypeError: Cannot read property 'forEach' of undefined"
import express from "express";
import fs from "fs";
const app = express();
fs.readdir('./routes', (err, fs) => {
fs.forEach(file => {
app.use('/', require('./routes/' + file))
});
})
export default app
This worked for me:
sync
fs.readdirSync('/some/path/routes').forEach(function(file) {
app.use('/', require(`/some/path/routes/` + file));
});
async
fs.readdir('/some/path/routes', function(err, files){
files.forEach(function(file){
app.use('/', require(`/some/path/routes/` + file));
});
});
You can do using fs.readdirSync because the server is not yet started.
fs.readdir(`${__dirname}/routes`, (err, files) => {
if (err)
console.log(err);
else {
files.forEach(file => {
app.use('/', require(`${__dirname}/routes` + file));
})
}
})
You can use fspromise and import to handle using promise. 🚀🚀🚀
import { promises as fsPromises } from 'fs';
export const init = async () => {
const files = await fsPromises.readdir(`${__dirname}/routes`);
const router = Router();
const createRoute = async (file) => {
const route = await import(`./routes/${file}`);
router.use("/", route.default);
};
await Promise.all(files.map(createRoute));
return router;
}
// app.js
import {init} from "./routes";
const app = express();
(async() => {
await init();
// Start server
})();
I would suggest doing like below. You will have more control over routes. You can do customization on routes bases if needed.
ex. /v1 and /v2 etc..
// routes/index.js
import { Router } from "express";
import route1 from './route1';
import route2 from './route2';
const router = Router();
[route1, route2].forEach((route) => router.use("/", route));
export default router;
// app.js
import express from "express";
import routes from "./routes";
const app = express();
app.use("/", routes);
export default app;

Using koa-views with TypeScript

I was trying to use koa-views as my renderer, but I kept getting the message from TS:
Property 'render' does not exist on type 'ParameterizedContext<any, IRouterParamContext<any, {}>>'.ts(2339)
My app.js
import Koa from "Koa";
import views from "koa-views";
import indexRouter from "./routes/index"
const app = new Koa();
app.use(views(`${__dirname}/views`, { autoRender: true, extension: "swig" }));
app.use(indexRouter.routes());
index.js - IndexRouter:
import Router from "koa-router";
const router = new Router();
router.get("/", async (ctx, next) => {
ctx.render(); // not done yet tho
await next();
})
export = router;
This is because argument ctx type doesn't have method render(), but in types lib #types/koa-views declared module (see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/koa-views/index.d.ts#L55).
And you can make this:
import { Context, DefaultState } from "koa";
import * as Router from "koa-router";
const router = new Router<DefaultState, Context>();
router.get("/", async (ctx: Context, next) => {
await ctx.render("/path/");
await next();
});

how to serve assets from Nest.js and add middleware to detect image request

I am trying to serve image from Nest.js server and add middleware to track all request but the only way I could make it work was with express
import { NestFactory } from '#nestjs/core';
import * as bodyParser from "body-parser";
import {AppModule} from "./app.module";
import * as path from "path";
import * as express from 'express';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(bodyParser.json({limit: '50mb'}));
app.use(function(req, res, next){
next();
});
//
app.use('/api/track/',express.static(path.join(__dirname, '/public'))); //Serves resources from public folder
app.use('/api/track/:img', function (req, res, next) {
console.log('do something');
next();
});
await app.listen(3333);
}
bootstrap();
How can I implement it with using the controller or middleware?
The nestjs doc tells you, how to serve static files. In short, here is how you do it:
Specify root directory of your assets in you main.ts
app.useStaticAssets(path.join(__dirname, '/../public'));
Use the #Res annotation to be able to use the sendFile method of express framework
#Get('track/:imgId')
test(#Param('imgId') imgId, #Res() res) {
const imgPath = getImgPath(imgId);
return res.sendFile(imgPath, { root: 'public' });
}
This solution assumes that your nestjs installation uses express under the hood.
Sources:
https://github.com/nestjs/nest/issues/402
https://docs.nestjs.com/techniques/mvc
Want to add a point here, please make sure you're using:
const app = await NestFactory.create<NestExpressApplication>(AppModule);
Instead of this:
const app = await NestFactory.create(AppModule);
in your main.ts file.
It worked for me. Just inject this controller in app module.
import { Controller, Get, Req, Res } from '#nestjs/common';
#Controller('uploads')
export class ServeFilesController {
#Get('products/images/:imageName')
invoke(#Req() req, #Res() res) {
return res.sendFile(req.path, { root: './' });
}
}

Why does importing a router for express in TypeScript not work

I am trying to set up a simple Hello World REST service using NodeJS and typescript. I want to separate the routers into different files, but somehow it doesn't work out.
Simply put, for a GET call to http://localhost:3000/welcome/hi , why does Project 1 work, but Project 2 not? I've tried to look for tutorials but the code doesn't seem to work the way I want them to.
Project 1
import express from "express";
import { Router, Request, Response } from "express";
const app: express.Application = express();
const port: any = process.env.PORT || 3000;
const router: Router = Router();
const welcomeRouter: Router = Router();
welcomeRouter.get("/", (req: Request, res: Response) => {
res.send({"message": "Welcome!"});
});
welcomeRouter.get("/:name", (req: Request, res: Response) => {
let { name } = req.params;
res.send(`Hello, ${name}!`);
});
router.get("/", (req: Request, res: Response) => {
res.send({"message":"Hello, World!"});
});
app.use("/", router);
app.use("/welcome", welcomeRouter);
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}/`);
});
Project 2
./app.ts
import { Router, Request, Response } from "express";
const router: Router = Router();
router.get("/", (req: Request, res: Response) => {
res.send({"message": "Welcome!"});
});
router.get("/:name", (req: Request, res: Response) => {
let { name } = req.params;
res.send(`Hello, ${name}!`);
});
export default router;
./server.ts
import express from "express";
import { Router, Request, Response } from "express";
import welcomeRouter from "./app";
const app: express.Application = express();
const port: any = process.env.PORT || 3000;
const router: Router = Router();
app.use("/welcome", welcomeRouter);
router.get("/", (req: Request, res: Response) => {
res.send({"message":"Hello, World!"});
});
app.use("/", router);
app.use("/welcome", welcomeRouter);
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}/`);
});
The order in which you "mount" or app.use each router matters. Also to go along with the order in which you mount them, the path matters as well. Think of them as a stack.
So for the first one you have:
/welcome -> welcomeRouter
/ -> router
So when you do GET http://localhost:3000/welcome/hi, the welcomeRouter will handle the request since it is the first one in the stack that matches the path /welcome.
Doing just GET http://localhost:3000/welcome yields {"message": "Welcome!"}, correct? Then finally doing a GET http://localhost:3000/welcome/hi yields: Hello hi.
For the second one you have:
/ -> router (I'm guessing this router refers to the one you defined in app.ts)
/welcome -> welcomeRouter
Within app.ts, where you export the router object, you have a route defined as /:name.
This will handle anything: /*. Meaning it will also handle /welcome where welcome becomes the name parameter.
So moving the welcomeRouter above the router should make it work like project 1.

nodejs combime with typescript

I try to use typescript with nodejs.
I don't understand why it show me error. Please help me fix it.
Here is my code (assum that I Import all module needed)
This is my index.ts file:
import routes from "./routes/routes";
let app = express();
app.use(routes);
This is my routes/routes.ts:
import * as homeRoute from "../apps/home/home.route";
let app = express();
export default function routes() {
app.use("./home", homeRoute); // It show error in path: "./home"
return app;
}
This is my home.route.ts
let router = express.Router();
router.get("/", HomeController.hello); // it show error that property "hello" not exist
// }
module.exports = "homeRoute";
This is my home.controller.ts:
exports.hello = function (req, res, next) {
console.log("Hello word");
}
In your home.controller.ts use an export statement instead:
export const hello = (req, res, next) => {
console.log("Hello word");
}
Then in your home.route.ts you have two ways of importing your controller method:
import * as HomeController from '../path/to/home.controller';
let router = express.Router();
router.get("/", HomeController.hello);
or
import {hello} from '../path/to/home.controller';
let router = express.Router();
router.get("/", hello);

Resources