Calling a method from another script throwing cannot find module - node.js

I have written this method here
In redisController.js
export default getAllKeysWithValue = async (req,res) => {
client.keys('*', (err, keys)=> {
if (err) return console.log(err);
for(let i =0;i<keys.length;i++){
client.get(keys[i],function(err,data){
console.log(`key is ${keys[i]} and value is ${data}`);
res.send("LOOK AT YOUR LOG :)")
})
}
});
}
And in the routes.js
import express from 'express'
import getAllKeysWithValue from "../controllers/redisController"
import getRedisValue from "../controllers/redisController";
import postRedisValue from "../controllers/redisController";
var router = express.Router();
router.get("/getAll",getAllKeysWithValue)
router.get('/getKey/:keyRedis',getRedisValue);
router.post('/createKeyValue',postRedisValue);
export default router;
And in the server.js
import express from 'express'
import bodyParser from 'body-parser';
import redisRoute from './routes/routes';
const app = express();
const PORT = 3001;
bodyParser.urlencoded({extended : false})
app.use(express.json())
app.use("/redisLogic",redisRoute);
app.listen(PORT,() =>{
console.log("SERVER r");
})
But iam getting Cannot find module 'C:\Users\me\OneDrive\Desktop\firstTask\routes\routes' imported from C:\Users\me\OneDrive\Desktop\firstTask\server.js
Did you mean to import ../routes/routes.js?
!Structure]1

A default import can be imported in another file as import myDefaultImport from './myFile.js'
You cannot have multiple default exports in one file. So in redisController.js export your functions as
// declare function
export function getAllKeysWithValue() { ... }
export function postRedisValue () { ... }
// the one allowed default export per file
export default myFunction() { ... }
In other file you import them as
import myFunction, { getAllKeysWithValue, postRedisValue } from `path-to-controller`
These are ES6 in/exports and straightforward.
The path and usage of your redisRouter is correct. I guess the error happens cause you have mutliple default exports.

It can be so simple as a piece of cake.
You're using the CommonJS in your back-end side.
Try using ES6 method.
Syntax :
const . . . = require('./')
Hint: If you want to have multiple defaults in JavaScript, you can do it through this syntax:
export default { Function1, Function2 }
Hint:
In NodeJS, It's better to use module.exports and exports.Function = ..
However, There's a difference between them that you can surf the Internet to check it out.

Related

is Express initialized first in Node initialization dependencies?

I'm having a problem during the initialization of a system. In order to initialize this system, I'm calling the index.ts file. This file imports an initializer class called StartServer. This class has an async method called start that initialize all the system database connections and express server. The problem is, somehow Node initialize express files, index.routes.ts, where the routes are defined, and all it dependencies, before starting the index file with the initializer class, generating an error of undefined due to no connections exits at this point.
index.ts file :
import { StartServer } from './services';
StartServer.start();
StarterServer.ts file :
export class StartServer {
public static async start(): Promise<void> {
try {
const configPort: IConfig = config.get('App.port');
await Connections.startDatabaseConnections();
const server = ServerFactory.create();
await server.init();
console.log(`Server is listening at port ${configPort}...`);
} catch (error) {
console.error((error as Error)?.stack);
}
}
}
ExpressServer.ts file :
import routes from '../routes/index.routes';
export class ExpressApp {
private app = express();
private port = config.get('App.port');
routes() {
this.app.use(routes);
}
async init() {
this.routes();
this.app.listen(this.port);
}
}
index.routes.ts file :
import express from 'express';
const router = express.Router();
router.get('/', (_, res) => {
res.status(200).json({ message: 'App listening...' });
});
export default router;
ServerFactory.ts file :
import { ExpressApp } from '#src/services';
export class ServerFactory {
public static create() {
return new ExpressApp();
}
}
In Node, import (and require) are synchronous. As soon as you require a file it is executed.
// a.js
import b from './b';
console.log('a.js');
//b.js
import c from './c';
console.log('b.js');
// c.js
console.log('c.js');
That will output:
c.js
b.js
a.js
In your case, the index.routes.ts will be executed as soon as it's required by ExpressServer.ts. One pattern to avoid initialisation is to export a factory function to perform the setup. You're doing this for your server already!
import express from 'express';
export default function createRouter() {
const router = express.Router();
router.get('/', (_, res) => {
res.status(200).json({ message: 'App listening...' });
});
}

How to pass sequelize through express routes to controller in MVC model in node when using ES6 import/export?

I'm trying to refactor some existing code into an MVC model, and am not sure if I'm messing up the structure, or if I just can't figure out how to pass a variable, but, assuming my structure is good, how do I pass a sequelize instance through an Express route to a controller? Here's my code, hopefully simplified for clarity:
Structure:
src/
db.js
routes.js
server.js
controllers/mycontroller.js
models/mymodel.js
server.js:
'use strict';
import express from 'express';
import Sequelize from 'sequelize';
import { router as routes } from './routes';
import db from './db';
const app = express();
try {
await db.authenticate();
console.log('Connection has been established successfully.');
} catch (error) {
console.error('Unable to connect to the database:', error);
}
db.myTable.sync(); // this works fine
app.use(express.urlencoded({ extended: false }));
app.use(routes); // this, I think, needs to pass db.myTable
app.listen( 3300, () => {
console.log('Listening on 3300');
});
db.js:
'use strict';
import Sequelize from 'sequelize';
import myTableModel from './models/mymodel';
const sequelize = new Sequelize('sqlite::memory');
const db = {};
db.authenticate = () => sequelize.authenticate();
db.myTable = myTableModel(sequelize);
export default db;
routes.js:
import express from 'express';
export const router = express.Router();
import MyController from './controllers/mycontroller';
const myController = new MyController();
... // other routes elided for brevity
router.post('/test', myController.store); // that db.myTable I thought I needed to pass above,
// I think I need to pass again here. Or, alternatively, I could put a constructor into
// MyController and pass it as an arg above when I call 'new MyController', but I still have to
// get it down here into this routes file.
mycontroller.js:
'use strict';
import MyTableModel from '../models/mymodel'; // This was an experiment I tried, but in retrospect,
// it of course makes no sense. I don't need to import the model, I need to have passed the
// instantiated model down here somehow
export default class MyController {
store = async (req, res, next) => {
await MyTable.create({ full: req.body.fullUrl}); // This fails (of course), because
// MyTable.create doesn't exist here.
res.redirect('/');
}
}
So, back to the question: assuming this structure looks correct (feel free to comment on that as well), how do I get that MyTable sequelize object passed all the way through to the controller, so it can do its thing?
Maybe in calling directly the model ?
'use strict';
import { myTable } from '../db';
export default class MyController {
store = async (req, res, next) => {
await MyTable.create({ full: req.body.fullUrl});
res.redirect('/');
}
}

Node REST API : Need to combine multiple routes in an object

I am building an application backend in TypeScript & NodeJS.
I have kept multiple routes logic in separate files(in single folder for each service) as :
> signup.ts // export { router as signupRouter };
> signin.ts // export { router as signinRouter };
> signout.ts // export { router as signoutRouter };
I need to do this for all the services in future.
I need to combine these routes so that I can specify them as a single entity in the index.ts file.
Something like:
import <object_that_combines_all> from './routes/<some_file_for_object>';
app.use('/api/users', require('./routes/users/<object_that_combines_all>'));
.
.
and so on
So that I don't have to mention each route explicitly in the index.ts file.
There is a simpler way using the router.use() method in which we can combine the individual endpoints.
Assuming your file structure looks something like this -
/src
/routes
/users
- signup.ts
- signin.ts
- signout.ts
index.ts (your main app entry point)
You can utilize the router.use() method provided by express.Router().
First, add a new index.ts file to the /routes/users folder to combine the multiple endpoints.
// /routes/users/index.ts
import * as express from 'express';
import { signupRouter } from './signupRouter';
import { signinRouter } from './signinRouter';
import { signoutRouter } from './signoutRouter';
const router = express.Router();
router.use(signupRouter);
router.use(signinRouter);
router.use(signoutRouter);
export {router as usersRouter};
Then in your main app entry point index.ts, do the following -
// /src/index.ts
import * as express from 'express';
import { usersRouter } from './routes/users/index.ts';
const PORT = process.env.PORT || 4000;
const app = express();
...
// Add your single entity entry point like this
app.use('/api/user', usersRouter);
...
app.listen(PORT, () => console.log(`Listening on port ${PORT}`)
To do that, you'll need to dynamically discover the filenames (readdir or similar) and use dynamic import to import them. Dynamic import (import()) returns a promise of the module namespace object for a module.
For instance, using the fs/promises version of readdir, something along these lines (off-the-cuff, some tweaking probably required):
import { readdir } from "fs/promises";
const directoryPath = "/path/to/the/files";
const rexIsRouterFile = /^.+\.ts$/i;
async function loadRoutes(app) {
const names = await readdir(directoryPath);
for (const name of names.filter(name => rexIsRouteFile.test(name))) {
const { router } of await import(`${directoryPath}/${name}`);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^−−−−−−− dynamic import
app.use('/api/users', router);
}
}
Note that this assumes you have a TypeScript loader setup (for instance, as with ts-node). If you don't, you'll need to compile those TypeScript files to JavaScript before this runs, then change .ts to .js in rexIsRouterFile.

Has no exported member

I am new in Typescript. I am using express js and I have the folowing problem. When I run the server it appear '...../routes.ts' has no exported member 'router'. I ve been searching but I didnt succeed. These are my files.
In my src/index.ts
import "reflect-metadata"
import * as express from "express"
import { router } from "./routes"
async function main() {
const app = express()
app.get('/api',router)
app.listen(3000, () => console.log("Server running"))
}
main()
In my src/routes.ts
import * as express from "express";
var router = express.Router();
router.route('/user').get((req, res) => res.send("Hello world"));
module.exports = router;
This isn't a Typescript issue, you aren't exporting router as a named export so the { ... } syntax won't work.
Given it appears to be the default export, you can use
import router from './routes.js'
Alternatively, if you are using a transpiler that supports the export syntax, you could export your router as a named export i.e.
export const router
This would allow you to import via { router }.

Defining a ExpressJS route from a Typescript class

I'm trying to load ExpressJS routes from a Typescript class. The idea is that this should eventually be dynamic routes. But I'm already stuck at defininghard coded routes in a class.
My index.ts js looks like this:
import generic = require('./generic');
import Generic = generic.Generic;
class Test {
private app:any;
private port:number = 3000;
constructor() {
this.app = express();
new Generic();
this.app.listen(this.port, () => {
console.log('Listening on port ' + this.port);
});
}
}
export = Test;
new Test();
Then my generic.ts looks like this. I'm trying to define another route from this class:
module Generic {
export class Generic {
constructor() {
console.log('In generic');
var router:any = express.Router();
router.get('/', function (req, res) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send("AAA");
});
}
}
}
export = Generic;
When I run my application then I see the message In generic appear in console. But when I load my browser it says:
Cannot GET /
So for some reason it's not really registering the route from the Generic class. What am I doing wrong?
Take a look at the sample on Microsoft's github page. Rather than using express.Router, they simply use get and import the function from an external module. It has worked pretty well for me.
app.ts
import * as express from "express";
import * as routes from "./routes/index";
var app = express();
app.get('/', routes.index);
routes/index.ts
import express = require("express")
export function index(req: express.Request, res: express.Response) {
res.render('index', { title: 'ImageBoard'});
};

Resources