I am creating a small project in node, i have routes of two tables, drums and pianos in same file named routes.js in two different function called drums() for drums and pianos() for pianos. i have exported both functions and both of them return router. Router is return value of express.Route() class.
I have used these two functions in index.js file by importing, i am accessing route by following code
app.use('/pianos', routes.pianos());
app.use('/drums', routes.drums());
But i am getting response from only one function, if i keep
app.use('/pianos', routes.pianos());
at first then i get list of pianos with url localhost/pianos and localhost/drums as well and if i keep
app.use('/drums', routes.drums());
at first then i get list of drums with url localhost/drums and localhost/pianos as well. What is mistake here?
const express = require('express');
const router = express.Router();
const joi = require('joi');
function drums(){
drums = [
{id:1, name:'Bongo drum'},
{id:2, name:'Bass drum'},
{id:3, name:'Ashiko'},
{id:4, name:'Basler drum'},
{id:5, name:'Cajón'}
];
router.get('/', (req, res)=>{
res.send(drums);
});
router.get('/:id', (req, res) =>{
const drum = drums.find( c=> c.id === parseInt(req.params.id));
if(!drum){
return res.status(404).send("Error: Drum is not available");
}
res.send(drum.name);
});
router.post('/', (req, res)=>{
const {error} = validator(req.body);
if(error) return res.status(400).send('Eror 400: Bad request', error.details[0].message);
const drum = {id:drums.length+1, name:req.body.name};
drums.push(drum);
res.send(drum);
}
);
router.put('/:id', (req, res)=>{
const drum = drums.find(c=> c.id === parseInt(req.params.id));
if(!drum) return res.status(404).send('Error: Drum is not available');
const {error} = validator(req.body);
if(error) return res.status(400).send('Error 400: Bad request', error.details[0].message);
drum.name = req.body.name;
res.send(drum);
});
return router;
}
function pianos(){
const pianos = [
{id:1, name:'Yamaha U1'},
{id:2, name:'Roland RD-2000'},
{id:3, name:'Nord Piano 4'},
{id:4, name:'Yamaha NU1X'},
{id:5, name:' Dexibell Vivo S7'}
];
router.get('/', (req, res)=>{
res.send(pianos);
});
router.get('/:id', (req, res)=>{
const piano = pioanos.find(c=> c.id === parseInt(req.params.id));
if(!piano) return res.status(404).send('Error:The piano is not available');
res.send(piano);
});
router.post('/', (req, res)=>{
const {error} = validator(req.body);
if(error) return res.status(400).send('Error-Bad request', error.details[0].message);
const piano = {id:pianos.length+1, name:req.body.name};
pianos.push(piano);
res.send(piano);
});
router.put('/:id', (res, req)=>{
const piano = pioanos.find(c=> c.id === parseInt(req.params.id));
if(!piano) return res.status(404).send('Error: Piano is the available');
const {error} = validator(req.body);
if(error) return res.status(400).send('Error:Bad request', error.details[0].message);
piano.name = req.body.name;
res.send(piano);
});
return router;
}
function validator(instrument){
const schema={
name:joi.string().min(5).required()
};
return joi.validate(instrument, schema);
}
module.exports.drums = drums;
module.exports.pianos = pianos;
MY index.js file is like this:
const mongoose = require('mongoose');
const express = require('express');
const app = express();
const debug = require('debug')('pm:index');
const routes = require('./routes/routes');
mongoose.connect('mongodb:localhost/planetmusic')
.then(()=> debug('Connected to database'))
.catch(err => debug('Error!!Could not connect to database', err.message));
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.use(express.static('public'));
app.use('/drums', routes.drums());
app.use('/pianos', routes.pianos());
const port = process.env.port || 5000;
app.listen(port, ()=> console.log(`listening at port: ${port}`));
If there are other better solution to manage my all routes then please help me.
taken that we should separate concerns, I would recommend split everything into files, it is easier to maintain and to add features in the future as everything is in it's own place...
in a NodeJs project, it is normal to encounter, in examples, some folder rearrangement, and I would suggest this:
.
├── package.json
└── server/
├── server.js
└── routes/
├── drums.js
├── index.js
└── piano.js
here is a very simple example, so you can understand how ExpressJs routes work when spread out upon multiple files:
server.js content
const express = require('express');
const routes = require('./routes');
const app = express();
const PORT = 5001;
app.use('/drums', routes.drums);
app.use('/pianos', routes.pianos);
app.use('/', (req, res) => { res.send({ action: 'default get' }); });
app.listen(PORT, () => {
require('./utilities/api-table')(app._router.stack);
console.log(`ready on http://localhost:${PORT}`);
});
server/routes/index.js content
const fs = require("fs");
const path = require("path");
const routing = {};
fs.readdirSync(__dirname) // read all files in this directory
.filter(
file =>
// only read .js files, but not the index.js (this file)
file.indexOf(".") !== 0 && file !== "index.js" && file.slice(-3) === ".js"
)
.forEach(file => {
const filename = file.replace(".js", "");
// attach the routes in it's own filename
routing[filename] = require(path.join(__dirname, file));
});
module.exports = routing;
drums.js and pianos.js content are exactly the same, just the "drums" and "pianos" change so we know we are reading from the correct file...
const express = require('express');
const router = express.Router();
const getAll = (req, res) => {
res.send({ action: 'GET all drums' })
};
const create = (req, res) => {
res.send({ action: 'POST drums', data: res.body })
};
const getById = (req, res) => {
res.send({ action: 'GET drums by id', id: req.params.id })
};
const editById = (req, res) => {
res.send({ action: 'PUT drums by id', id: req.params.id })
};
const deleteById = (req, res) => {
res.send({ action: 'DEL drums by id', id: req.params.id })
};
router.get('/', getAll);
router.post('/', create);
router.get('/:id', getById);
router.put('/:id', editById);
router.delete('/:id', deleteById);
module.exports = router;
when you fire up the server up, you will get all this routes:
and output as
full project (though it's very simple) can be found on GitHub
Related
///index.js
const functions = require("firebase-functions");
const express = require("express");
const app = express();
const productRouter = require('./routes/productRoutes');
const globalErrorHandler = require('./controllers/errorController');
const AppError = require('./utils/appError');
// Compressing upcompressed files which is been sent to client such text.
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}
// app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.send('Hello World')
});
app.get('/homepage', (req, res) => {
res.send('Hello People of God')
});
app.use('/products', productRouter);
// Handing Unhandled Routes
app.all('*', (req, res, next) => {
next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});
app.use(globalErrorHandler);
exports.app = functions.https.onRequest(app);
///productRoutes.js
const express = require('express');
const {
getProduct,
getAllProduct,
} = require('./../controllers/productController');
const router = express.Router();
router
.route('/')
.get(getAllProduct);
router
.route('/:id')
.get(getProduct);
module.exports = router;
///productController.js
const AppError = require('../utils/appError');
const Product = require('../modals/productModels');
const catchAsync = require('../utils/catchAsync');
// GET SINGLE PRODUCT CONTROLLER
exports.getProduct = catchAsync(async (req, res, next) => {
const product = await Product.findById(req.params.id)
.populate('reviews');
if (!product) {
return next(new AppError('No product found with that ID', 404));
}
res.status(200).json({
status: 'success',
data: {
product
}
});
});
// GET ALL PRODUCT CONTROLLER
exports.getAllProduct = catchAsync(async (req, res, next) => {
const products = await Product.find();
res.status(200).json({
status: 'success',
results: products.length,
data: {
products
}
});
});
///server.js
const mongoose = require('mongoose');
const app = require('./index')
const dotenv = require('dotenv');
// CONNECTING TO MONGODB SERVER
dotenv.config({ path: './config.env' })
const DB = process.env.DATABASE.replace('<PASSWORD>', process.env.DATABASE_PASSWORD);
mongoose.connect(DB, {
useNewUrlParser: true,
safe: true,
strict: false,
useUnifiedTopology: true
}).then(con => console.log('DB connection successful'))
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`App running on port ${port}...`);
});
After running function serve on my terminal i can access the two '/' and 'homepage' app.get which return the res "Hello world" and "Hello people of God" but can't access app.use('/products', productRouter). Its does take some time to run and throw an error "{"code":"ECONNRESET"}" please why is this so.
Am expecting to get my list of products from my mongodb data base.
so I am getting the the error : TypeError: app.use() requires a middleware function.
I am unsure why i made sure i exported the file, but I am a bit confused why. I think i linked it up correctly in my server file as well.
const express = require('express')
const mongoose = require('mongoose')
const morgan = require('morgan')
const app = express()
const bodyParser = require('body-parser')
app.use(morgan('dev'))
require('dotenv').config()
const { expressjwt: jwt } = require("express-jwt")
app.use(bodyParser.json())
mongoose.connect('mongodb://localhost:27017/recipe', ()=> console.log('connected to database'))
app.use('/auth', require('./routes/authRouter'))
app.use("/api", jwt( {secret: process.env.SECRET, algorithms: ['HS256']}))
app.use('/api/recipe/', require('./routes/recipeRoutes'))
app.use('/api/public/'), require('./routes/publicDelete')
app.use('/api/comments/', require('./routes/commentRouter'))
app.use('/api/ingredients/', require('./routes/ingredRouter'))
app.use((err,req,res,next)=>{
console.log(err)
if(err.name ==='UnauthorizedError'){
res.status(err.status)
}
return res.send({message:err.message})
})
app.listen(8000, ()=>{
console.log('hello ')
})
const express = require('express')
const publicDeleteRouter = express.Router()
const Recipe = require('../models/recipe')
const User = require('../models/user')
publicDeleteRouter.delete('/:recipeId', (req, res, next) =>{
Recipe.findOneAndDelete({idMeal: req.params.recipeId, user: req.auth._id}, (err, deletedRecipe) => {
if(err){
console.log(idMeal)
res.status(404)
return next(err)
}
console.log('successfully deleted: ', deletedRecipe)
return res.status(200).send(`Successfully deleted ${deletedRecipe}`)
})
})
module.exports = publicDeleteRouter
I am using Multer Node JS package to upload files to my app sever , the code is basically typical upload file code
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
But each time a file is being uploaded the Node server becomes unresponsive and frontend from other request doesnt receive any response from other APIs until the file is uploaded.
Whats the best way to tackle this ?
In your sample code, you must just send a response to the client by res.json() or res.end() :
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
res.status(204).end();
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
res.status(204).end();
});
i can give you an example of how i implemented an imageupload in my app. it the code to upload a profile image for a user. i am also using multer middleware so it shoulder be similiar for you:
code is as follows:
// multer middleware:
const multer = require('multer');
const MIME_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
};
module.exports = storage = multer.diskStorage({
destination: (req, file, cb) => {
const isValid = MIME_TYPE_MAP[file.mimetype];
let error = new Error('invalid mime type');
if (isValid) {
error = null;
}
cb(error, 'images');
},
filename: (req, file, cb) => {
const name = file.originalname.toLowerCase().split(' ').join('-');
const ext = MIME_TYPE_MAP[file.mimetype];
if (name.includes('.' + ext)) {
cb(null, name)
} else {
cb(null, name + '.' + ext);
}
},
});
and here the code in the service handling the fileupload
// profile service in backend written in express
exports.uploadImage = (req, res, next) => {
const url = req.protocol + '://' + req.get('host');
profileRepository
.findOne({ _id: req.params.id })
.then((response) => {
const fetchedUser = response;
fetchedUser.imagePath = url + '/images/' + req.file.filename;
profileRepository
.updateOne({ _id: req.params.id }, fetchedUser)
.then((response) => {
return res.status(200).json({
message: 'profileimage updated',
});
})
.catch((error) => {
return res.status(500).json({
message: 'uploading image failed',
});
});
})
.catch((error) => {
return res.status(404).json({
message: 'fetching user failed',
});
});
};
then i use the middleware in my profile routes file like this:
// profile.routes.js
const express = require('express');
const ProfileController = require('./profileController');
const checkAuth = require('../middleware/checkAuth');
const router = express.Router();
const fileStorage = require('../middleware/fileStorage');
const multer = require('multer');
// imageUpload
router.post('/user/image/:id', checkAuth, multer({storage: fileStorage}).single('image'), ProfileController.image);
my Controller then calls the service function with the actual business logic like this:
// profile.controller.js
const profileService = require('./profileService');
exports.image = (req, res, next) => {
return profileService.uploadImage(req, res);
};
and finally my route is used by my app.js file like this:
// app.js
const express = require('express');
const profileRoutes = require('./profile/profileRoutes');
const app = express();
// set images path for saving images on server
app.use('/images', express.static(path.join('images')));
app.use('/api', profileRoutes);
module.exports = app;
i hope i was able to point you in the right direction with my example
I am trying to build a webchat app using node.js and express. I have a router file and a server file, together with some client files. I would like to emit a join event from the router and processing it on the server so the user can join the room. I did i like this
Server.js
const express = require('express');
const layout = require('express-layout');
const app = express();
var server = require('http').createServer(app);
var io=require('socket.io')(server);
const routes = require('./router')(io);
const bodyParser = require('body-parser');
var fs = require("fs");
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
const middleware = [
layout(),
express.static(path.join(__dirname, 'public')),
bodyParser.urlencoded(),
];
app.use(middleware);
app.use('/', routes);
app.use((req, res, next) => {
res.status(404).send("Sorry can't find that!");
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
io.on('connect', onConnect);
function onConnect(socket) {
var contents = fs.readFileSync("./public/rooms.json");
let rooms = JSON.parse(contents);
socket.emit('parse',rooms);
socket.on('join',function (name, room) {
console.log(name+" "+ room);
socket.join(room);
socket.user=name;
socket.room=room;
})
}
Here I just initialize the io connection together with all the dependencies I use. I use const routes = require('./router')(io); to pass the io variable
router.js
const express = require('express');
const User= require("./public/classes/User");
const router = express.Router();
const {check, validationResult} = require('express-validator');
const {matchedData} = require('express-validator/filter');
var userlist=new Array();
router.get('/', (req, res) => {
res.render('index', {
data: {},
errors: {}
})
});
router.post('/enter', [
check('username')
.isLength({min: 1})
.withMessage('Username is required').trim() //implement personalized check
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.render('index', {
data: req.body,
errors: errors.mapped()
})
}
const data = matchedData(req)
handleJoin(data);
});
return router;
//MOVE TO SUPPORT
function find(name) {
return 1;
}
function handleJoin (data){
if(find(data.username)){
const newUser= new User (data.username, data.room,"");
userlist.push(newUser);
io.emit('join',newUser.name,newUser.room);
}
};
};
The console should log the name and the choosen room but it doesn't. How do I process this?
I'm currently building an app and I have a routes file that looks like this.
const router = require('express').Router();
router.get('/', (req, res) => res.render('statics/home'));
router.get('/jobs', (req, res) => res.render('statics/jobs'));
router.get('/about-page', (req, res) => res.render('statics/about-page'));
router.get('/valves', (req, res) => res.render('statics/valves'));
router.all('*', (req, res) => res.notFound());
module.exports = router;
I am trying to figure out a way to refactor my routes and have a single route that accepts any string and then checks to see if a file exists matching it
Any help appreciated!
To easily handle static file, you can use express static, express will automatic route all file inside static folder
app = require('express')();
app.use('statics',express.static('statics'));
Something like this could work:
const router = require('express').Router();
const fs = require('fs');
router.get(':template', (req, res) => {
const tpl = req.param('template');
if (tpl) {
if (fs.existsSync('/path/to/templates/' + tpl + '.ext')) { // adjust the path and template extension
res.render('statics/' + tpl);
} else {
res.notFound();
}
} else {
res.render('statics/home');
}
});
router.all('*', (req, res) => res.notFound());
module.exports = router;
Or probably better approach would be to read the templates directory once and create routes based on its contents:
const router = require('express').Router();
const fs = require('fs');
const templates = fs.readdirSync('/path/to/templates');
templates.forEach(tpl => {
tpl = tpl.substring(tpl.lastIndexOf('/') + 1);
if (tpl === 'home') {
router.get('/', (req, res) => res.render('statics/home'))
} else {
router.get('/' + tpl, (req, res) => res.render('statics/' + tpl))
}
});
router.all('*', (req, res) => res.notFound());
module.exports = router;