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 }.
Related
I'm using the express framework in NodeJS with typescript in the backend.
I have a very easy architecture in my index file:
index.html
import express = require("express");
import mongoClient = require("mongodb");
import apiRoutes from "./routes";
import { MONGO_CONNECTION } from "./config/mongo_config";
const app = express();
mongoClient.MongoClient.connect(MONGO_CONNECTION, { }, (err: any, mclient: any) => {
if (err) throw err;
const mongodb = mclient.db('test');
app.use('/api', isOnline, apiRoutes);
app.listen(80, () => console.log('API running on port 80'));
});
The express routes are separated in an other file (in my version it is separated in multiple file, just to keep it simple), here just an example:
routes/index.ts
import express = require("express");
import { Router } from "express";
const router = Router({mergeParams: true});
router.get('/example', (req: express.Request, res: express.Response) => {
res.json('Hello World');
});
export default router;
I don't want to use mongoose. So is there any way to pass the DB connection to another file without connecting again?
You can export an object in your index.js
export const mongodb = {};
And then instead of this:
const mongodb = mclient.db('test');
Use:
mongodb.connection = mclient.db('test');
or something like this.
Then other parts of the code can import it but make sure that it is not undefined before you use it because it may have not been initialized yet.
Another option would be to export a promise that would be resolved with a connection established:
export const mongodb = new Promise((resolve, reject) => {
// establish your connection here ...
resolve(mclient.db('test'));
// ...
);
And then in your importing code you will also use it with await.
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.
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.
I use TypeScript for my Express app. I distributed the registration of certain endpoints across several other modules. These modules import main.ts and register them (see depFoo.ts). Unfortunately they don't seem to be registered and because app starts listening before deppFoo.ts executed it's registration!?
What is a proper way in TypeScript to fix this Heg-Enn problem? Can I register a callback that gets executed once TypeScript resolved all modules?
main.ts
depFoo.ts
main.ts
export const app: express.Application = express();
app.listen(3000, function () {
console.log("App is listening on port 3000!");
});
depFoo.ts
import { app } import "./main.ts"
app.get(...);
This tutorial gives a great explanation of the router style system with express TS. One of the cleaner ways to do it is to have a routes directory with files similar to
import * as express from "express";
export const register = ( app: express.Application ) => {
app.get( "/", ( req: any, res ) => {
res.render( "index" );
} );
};
and then in your main app file you can use
import * as routes from './routes'
...
const app = express()
routes.register(app)
Which makes your main file a whole lot cleaner and your endpoints more modular.
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'});
};