How to read all routes dynamically in node.js - 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;

Related

Piping the openDownloadStream() of MongoDB gridFS bucket with a createWriteStream () writes an empty file

I referenced GridFS-download files to download the files stored in mongoDB but it writes an empty file. I have made sure that the files in my database aren't empty.
server.js:
import fs from "fs";
import path from "path";
import express from "express";
import "dotenv/config";
import { db, bucket, connectToDb } from "./db.js";
import { fileURLToPath } from "url";
import cors from "cors";
import { ObjectId } from "mongodb";
const app = express();
app.use(express.json());
app.use(cors());
const PORT = process.env.PORT || 8000;
app.get("/", async (req, res) => {
const cursor = bucket.find({});
const songInfo = await cursor.toArray();
console.log("id", songInfo[0]._id);
bucket.openDownloadStream(songInfo[0]._id).pipe(fs.createWriteStream('./outputFile.mp3'));
res.json(songInfo);
});
connectToDb(() => {
console.log("Successfully connected to database!!");
app.listen(PORT, () => {
console.log("Server is listening on port " + PORT);
});
});
db.js:
import { GridFSBucket, MongoClient } from "mongodb";
let db, bucket;
async function connectToDb(cb) {
const client = new MongoClient(`mongodb+srv://${process.env.MONGO_USERNAME}:${process.env.MONGO_PASSWORD}#cluster0.0xbmpug.mongodb.net/?retryWrites=true&w=majority`);
await client.connect();
db = client.db("musix");
bucket = new GridFSBucket(db);
cb();
}
export { db, bucket, connectToDb };
The files are audio files(.mp3). Is there a way I can download them. I would prefer not using mongoose.
I tried:
var fs_write_stream = fs.createWriteStream('./newAudio.mp3');
var readstream = bucket.createReadStream({_id: songInfo[0]._id});
readstream.pipe(fs_write_stream);
fs_write_stream.on("close", function () {
console.log('File has been written fully!')
});
but these returned error as createReadStream not a function.

Why is my post route not running properly in Express app?

I am trying to add a route to '/signup' in my express application. But, every time I am sending a post request to the server it is resolving in "No response". Whereas the '/' route is working. Where have I gone wrong with the code?
index.js
import dotenv from "dotenv";
import cors from "cors";
import morgan from "morgan";
import dbConnect from "./config/dbConnect.js";
import { authRoute } from "./routes/auth.js";
dotenv.config();
const port = process.env.PORT;
const DATABASE_URI = process.env.DATABASE_URI;
const app = express();
dbConnect();
app.get("/", (req, res) => {
res.sendStatus(200);
});
app.use(express.json());
app.use(cors());
app.use(morgan("combined"));
app.use("/api/v1", authRoute);
app.listen(port, () => {
console.log(`Server running at ${port}...`);
});
auth.js
import { Router } from "express";
const router = Router();
router.post("signup", (req, res) => {
const password = req.body.password;
console.log(password);
});
export { router as authRoute };
dbConnect.js
import mongoose from "mongoose";
import dotenv from "dotenv";
dotenv.config();
const DATABASE_URI = process.env.DATABASE_URI;
const dbConnect = () => {
mongoose.set("strictQuery", false);
mongoose
.connect(DATABASE_URI)
.then(() => {
console.log("connected");
})
.catch((error) => {
console.error(error);
});
};
export default dbConnect;
router.post("signup", (req, res) => {
const password = req.body.password;
console.log(password);
});
The client doesn't get a response because you haven't written any code to send a response.
You completely ignore the object passed to res.
You don't call res.json or res.render or res.send or any of the other methods that would send a response.
Seems like the problem was with my VSCode extension RapidApi client, tried using insomnia and it worked out fine. Sorry for the trouble!

MERN Heroku returns index.html instead of actual JSON data from server

this was working perfectly fine with localhost but after I deployed from Heroku it doesn't work.
please help.
Index.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const userRoute = require("./routes/users");
const authRoute = require("./routes/auth");
const postRoute = require("./routes/posts");
const multer = require("multer");
const path = require("path");
dotenv.config();
mongoose.connect(
process.env.MONGO_URL,
() => {
console.log("Connected to MongoDB");
}
);
app.use("/img", express.static(path.join(__dirname, "public/images")))
//middleware
app.use(express.json());
app.use(helmet());
app.use(morgan("common"));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, req.body.name);
}
});
const upload = multer({storage});
app.post("/api/upload", upload.single("file"), (req,res)=>{
try {
return res.status(200).json("file uploaded successfully");
} catch(err){
console.log(err);
}
})
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'frontend/build')));
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'frontend/build', 'index.html'));
});
}
app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/posts", postRoute);
//const port = parseInt(process.env.PORT) || 8800;
app.listen(process.env.PORT || 8800, () => {
console.log("backend server is running");
});
Feed.jsx
import "./feed.css";
import Share from "../share/Share";
import Post from "../post/Post";
import { useEffect, useState, useContext } from "react";
//import {Posts} from "../../dummyData";
import {axiosInstance} from "../../config";
import { AuthContext } from "../../context/AuthContext";
export default function Feed({username}) {
const [posts, setPosts] = useState([]);
const { user } = useContext(AuthContext);
//this helps you to render once when the page open. and only re-render whatever you put in[] changes, which is the dependency
useEffect(() => {
const fetchPosts = async () => {
const res = username
? await axiosInstance.get("/posts/profile/" + username)
: await axiosInstance.get("/posts/timeline/" + user._id);
console.log(user._id);
console.log(username);
console.log(res.data);
setPosts(
res.data.sort((p1,p2)=>{
return new Date(p2.createdAt) - new Date(p1.createdAt);
})
);
};
fetchPosts();
},[username, user._id])
return (
<div className="feed">
<div className="feedWrapper">
{(!username || username === user.username) && <Share/>}
{posts.map((p) => (
<Post key={p._id} post={p}/>
))}
</div>
</div>
);
}
if I do Console.log(res.data) from Feed.js, I see index.html data instead of JSON data I should be getting from "api/posts/timeline/"...
this was working perfectly fine with localhost but after I deployed from Heroku it doesn't work.
please help.

Expess node Error : Throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))

server/src/index.js
import './env';
import fs from 'fs';
import cors from 'cors';
import path from 'path';
import helmet from 'helmet';
import morgan from 'morgan';
import express from 'express';
import favicon from 'serve-favicon';
import bodyParser from 'body-parser';
import compression from 'compression';
import * as Sentry from '#sentry/node';
import routes from './api/routes';
import json from './api/middlewares/json';
import logger, { logStream } from './utils/logger';
import * as errorHandler from './api/middlewares/errorHandler';
import initMongo from './config/mongo';
// Init MongoDB
initMongo();
// Initialize Sentry
// https://docs.sentry.io/platforms/node/express/
Sentry.init({ dsn: process.env.SENTRY_DSN });
// Initialize Express
const app = express();
const APP_PORT =
(process.env.NODE_ENV === 'test' ? process.env.TEST_APP_PORT : process.env.APP_PORT) || process.env.PORT || '3000';
const APP_HOST = process.env.APP_HOST || '0.0.0.0';
const pathToSwaggerUi = require('swagger-ui-dist').absolutePath();
app.set('port', APP_PORT);
app.set('host', APP_HOST);
app.locals.title = process.env.APP_NAME;
app.locals.version = process.env.APP_VERSION;
// This request handler must be the first middleware on the app
app.use(Sentry.Handlers.requestHandler());
app.use(express.static(path.join(__dirname, './public')));
app.use(cors());
app.use(helmet());
app.use(compression());
app.use(morgan('tiny', { stream: logStream }));
app.use(bodyParser.json());
app.use(errorHandler.bodyParser);
app.use(json);
// API Routes
app.use('/api', routes);
// Swagger UI
// Workaround for changing the default URL in swagger.json
// https://github.com/swagger-api/swagger-ui/issues/4624
const swaggerIndexContent = fs
.readFileSync(`${pathToSwaggerUi}/index.html`)
.toString()
.replace('https://petstore.swagger.io/v2/swagger.json', '/api/swagger.json');
app.get('/', (req, resp) => resp.sendFile(path.resolve(path.join(__dirname, './public', 'index.html'))));
app.get('/api-docs/index.html', (req, res) => res.send(swaggerIndexContent));
app.get('/api-docs', (req, res) => res.redirect('/api-docs/index.html'));
app.use('/api-docs', express.static(pathToSwaggerUi));
// This error handler must be before any other error middleware
app.use(Sentry.Handlers.errorHandler());
// Error Middlewares
app.use(errorHandler.genericErrorHandler);
app.use(errorHandler.methodNotAllowed);
app.listen(app.get('port'), app.get('host'), () => {
logger.info(`Server started at http://${app.get('host')}:${app.get('port')}/api`);
});
// Catch unhandled rejections
process.on('unhandledRejection', err => {
logger.error('Unhandled rejection', err);
try {
Sentry.captureException(err);
} catch (err) {
logger.error('Raven error', err);
} finally {
process.exit(1);
}
});
// Catch uncaught exceptions
process.on('uncaughtException', err => {
logger.error('Uncaught exception', err);
try {
Sentry.captureException(err); } catch (err) {
logger.error('Raven error', err);
} finally {
process.exit(1);
}
});
export default app;
server/src/api/routes/quizz.js
import express from 'express';
import passport from'passport';
import * as quizzController from '../controllers/quizz';
const router = express.Router();
const requireAuth = passport.authenticate('jwt', {
session: false,
});
/**
* GET /api/quizz
*/
router.get('/all', quizzController.fetchAll);
export default router;
server/src/api/routes/index.js
import express from 'express';
import fs from 'fs';
import { removeExtensionFromFile } from '../middlewares/utils';
import swaggerSpec from "../../utils/swagger";
import * as utils from '../middlewares/utils';
const router = express.Router();
const routesPath = `${__dirname}/`;
const isDynamicImport = routeFile =>
routeFile !== 'index' && routeFile !== 'auth';
/*
* Load routes statically and/or dynamically
*/
/**
* GET /api/swagger.json
*/
router.get('/swagger.json', (req, res) => {
res.json(swaggerSpec);
});
// Load Auth route
router.use('/', require('./auth'));
// Loop routes path and loads every file as a route except this file and Auth route
fs.readdirSync(routesPath).filter(file => {
// Take filename and remove last part (extension)
const routeFile = removeExtensionFromFile(file);
// Prevents loading of this file and auth file
return isDynamicImport(routeFile)
? router.use(`/${routeFile}`, require(`./${routeFile}`))
: '';
});
router.get('/', (req, res) => {
res.json({
app: req.app.locals.title,
apiVersion: req.app.locals.version
});
});
/*
* Handle 404 error
*/
router.use('*', (req, res) => {
utils.handleError(res, {
code: 404,
message: 'URL_NOT_FOUND',
});
});
export default router;
I am trying to get a list of all the quizzes but it returns this error
"throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))"
If someone has been in the same situation please help me please
You should check all your JavaScript files. It seems that this line is missing in any JS file:
module.exports = router

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();
});

Resources