I am new to NodeJS. What I wanted to know is, can I like call 2 JS files using NodeJS & ExpressJS. Basically I want to have 2 seperate files so I can work on one and my partner can work on another one. So I want Server.js to call one file which contains some part of my REST API and other one contains rest of the function.
|--NodeModules[etc..]
|--Server.js
|--Rest/
| |--RestAPI1.js
| |--RestAPI2.js
It will be really helpful in the development of my project, if this is possible.
You can define routes in different files like this:
Server.js
var express = require('express')
var router1 = require("./routers/router1");
var app = express();
.....
app.use("/user", router1);
Router1.js
var router = require("express").Router();
router.get("/", function(req, res) {
...
});
module.exports = router;
Related
So I'm not really sure if the title is descriptive enough, but here is a super simple example.
My site has a public area and a restricted admin area.
example.com/admin (admin home page)
example.com/admin/news (news page)
example.com/admin/posts (posts page)
And because I don't want people who aren't administrators or logged in to be able to access it, I have a simple middleware function to check for cookies.
app.js
const express = require('express');
const app = express();
const authMiddleWere = async (req, res, next) => {
// pseudo-code, do some cookie validity check here
console.log(`Route: ${req.url}`)
if (cookie) {
next();
}
};
const adminRouter = require('./routes/private/home');
const newsRouter = require('./routes/private/news');
const postsRouter = require('./routes/private/posts');
app.use('/admin/', authMiddleWere, adminRouter);
app.use('/admin/news', authMiddleWere, newsRouter);
app.use('/admin/posts', authMiddleWere, postsRouter);
/routes/private/home.js
const express = require('express');
const router = express.Router();
router.get('/', async (req, res, err) => {
res.render('private/home');
});
module.exports = router;
The problem here is that this authMiddleWere function gets called twice when I visit nested paths such as example.com/admin/news which shares the same pattern - it's starting with /admin/......
I can tell that for sure because we are logging the req.url in our middleware function so if I go to example.com/admin it will log out:
Route: /
But if I go to example.com/admin/news it will log out both:
Route: /
Route: /news
So what is causing this and how do I work my way around it? I'm assuming that what I described is the intended behavior of Express.js so I am looking for a way to get around this or (re)structure my code better.
Cheers!
You can use a regex for your route.
app.use(/\/admin$/, authMiddlewear, authRouter);
This will match only routes that end in admin. You may need to handle cases where the route is /admin/ instead of /admin, but iirc, express handles that intelligently.
Well one way you can fix this is by creating a separate route file and splitting everything into a MVC manner. For example:
Inside your main app.js just create a route pointing to the /admin like so:
app.use('/admin', authMiddleWere, require('./src/your-route-to-the-file/admin.route'));
Inside the admin.route file, call your controller like this:
const express = require("express");
const router = express.Router();
const mainAdminCtrl = require("../controllers/admin.controller");
router.get("/news", mainAdminCtrl.adminAuthDisplay);
module.exports = router;
Where the const mainAdminCtrl is your controller and the function adminAuthDisplay is your service.
Essentially, you are splitting your functionality in to a dedicated router, controller and service file. So when you try to access the route /admin, it will look for any suffix inside the router file.
In a case where you want to access the /news endpoint, your API will only make the call once.
If this helps, I can expand my explanation further.
I have an Express app whose server.js file has maybe 30 GET and POST endpoints, like this:
const express = require('express');
const app = express();
const http_port = 8000;
app.listen(http_port,()=>{
console.log(`app listening on port ${http_port}`);
});
app.get('/create_something',function(req,res){
createSomething();
res.send('create');
});
app.post('/update_something',function(req,res){
updateSomething();
res.send('update');
});
//and so on for 30 more endpoints
For ease of maintenance, I want to break this set of endpoints up into different files, e.g. video.js and audio.js.
Thinking this solution might help, I created another file other_route.js:
var express=require('express');
var router=express.Router();
router.get('/other_route_endpoint',function(req,res){
res.send('other_route_endpoint');
});
module.exports.router=router;
and then including this in server.js by changing my initial declarations to:
const express = require('express');
const app = express();
const http_port = 8000;
var router=express.Router();
router.use('/other_route',require('./other_route').router);
But when I visit myserver.com:8000/other_route_endpoint, I get this error:
Cannot GET /other_route_endpoint
How can I add in endpoints from other files into server.js, so I can move some of its many endpoints into these subfiles?
First, your main file should not be using a router. Change the line to app.use('/other_route',require('./other_route').router);.
Second: each path you set with router.use in the routing file will be relative to the path specified in app.use. See https://expressjs.com/en/guide/routing.html#express-router
For example, if you have this in your main file
app.use('/foo', require('./bar.js'));
And this in bar.js
router.get('/bar', /* do something */);
Then the corresponding endpoint would be /foo/bar.
I am trying to take a user input and save it to a collection in my database. I am using Node.js, mongodb, mongoose, express.js and ajax.
I am currently trying to take the post when the user submits the form and take the input and save it to my data base from inside of my module.exports in my controller file.
I was able to make this work when all of the code was in one place inside the server.js but in an attempt to break my code apart appropriately I am trying to separate into a MVC system.
My addProductGroup controller looks like this:
//bring in models of data
var groups = require('../models').Groups;
var express = require('express');
var app = express();
//page functions go inside of module.exports
module.exports = {
index: function(req, res){
groups.find({}, function(err, groups){
if(err){
console.log(err);
}else{
res.render('addProductGroup',{title: 'Admin Add Group', adminloggedin: true, subtitle: 'Add a Group', underheaderp: ''});
app.post('/admin/addProductGroup', function(req,res){
var newGroupName = req.body.groupname;
new groupName({
groupName: req.body.groupname,
}).save(function(err, doc){
if(err){
res.json(err)
}
else {
res.render('addProductGroup',{title: 'Admin ASS Group', adminloggedin: true, subtitle: 'Add a Group', underheaderp: ''});
}
});
});
}
});
}
}
My controller is getting my data from my groups collection and then rendering my page. Then when the user posts the data I am trying to make it take the post data, save it to my database and then render the same exact page. I have played a lot with the nesting of my functions and order of operations.
My groups.js Model :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var GroupsSchema = new Schema ({
groupName: String
});
module.exports = mongoose.model('groups', GroupsSchema);
var groupName = module.exports;
I am using a handlebars template for my views.
So is having all of this in my module.exports a possible thing to accomplish?
Do i need to try and write a function outside of my module.exports to make this work?
If you need to see any of my other files just let me know.
Any help is greatly appreciated.
You do not clarify the issue you have, so I will try to provide you some general help:
Concerning organizing your express application you definitly should take a look at the Version 4 introduced Routers.
You can bind your routes directly on the router object and so seperate your logic into different files (modules).
Your party.js router could look like:
var express = require('express').Router()
router.get('/paricipants', function(req, res) {
res.send('dave','mike')
})
module.exports = router
You can have several such routers (controllers) in your controllers directory (i.e. /controllers). Taking full advantage of the module.exports functionality, you may now put an index.js file in this directory, which then will be loaded by default, as you require the directory.
Your index.js file in your controllers directory could look like:
var router = require('express').Router()
router.use('/party', require('./party'))
// Your other routes to controllers and eventually global routes here.
module.exports = router
You can then simply require this one module in your app.js:
var app = express()
app.use(require('./controllers'))
...
Now just require your mongoose models inside your controllers as you need them.
This will give you a more modular and structured application design.
Hope it helps.
The way I desgined my express nodejs application as per below;
app.get('/', page.index);
//Add new,edit and delete form
app.get('/approval', page.approval);
//Task to approve/reject the subordinate form
app.get('/task', page.task);
//Report
app.get('/report', page.report);
//Admin
app.get('/admin', page.admin)
app.listen(3000);
Hence I can always access using the url i.e
http://<Servername>:3000/
http://<Servername>:3000/approval
http://<Servername>:3000/task
Lets say now I will need to have a parent app root as appsA ( ie.
http://<Servername>:3000/appsA/
http://<Servername>:3000/appsA/approval
http://<Servername>:3000/appsA/task
How can I do that from express/nodejs without go and add appsA as a url on each of the get request.
You can use router to do that, example
var express = require("express");
var router = express.Router();
router.get('/', page.index);
router.get('/approval', page.approval);
router.get('/task', page.task);
router.get('/report', page.report);
router.get('/admin', page.admin)
// Then implement root route path
app.use("/appsA", router);
Note: Routers are only available for Express 4 and above, This solution will not work on all Express versions below version 4, If you still want to do this with express 3, you can implement your own Router middleware
I've got a page which is "Google Card" designed. I want to render some views on the cards of this main page.
The Cards interface looks like this:
Because there can be many cards, I organized my project in modules.
(BTW, if you know a framework thats fits more my project than Express does, can you tell it to me? :) )
I'm using Node.js with the Express Framework. My directory structures is this:
|-app
|--modules
|---weather
|---index.js
|----views
|-----weather.jade
|--views
|--config.js
|--server.js
|-public
|--assets
|---img
|---css
|---...
Here is some of my current code:
server.js:
var express = require('express');
var app = express();
app.use("/public", express.static(__dirname + '/../public'));
app.set('view engine', 'jade');
Board = {};
Board.modules = {};
Board.modules.weather = require('./modules/weather');
app.use(Board.modules.sticks);
app.get('/', function(req,res){
tpl = {};
tpl.modules = Board.modules;
console.log(tpl);
res.render(__dirname + '/views/board.jade', tpl);
});
app.listen(8080);
board.jade (the main page)
doctype html
html(lang="fr")
head
meta(charset="utf-8")
title Board
block stylesheets
link(rel="stylesheet", href="/public/assets/css/reset.css")
link(rel="stylesheet", href="/public/assets/css/board.css")
body
// Background
div.bg
// Header
header.topinfo
span.left.ip
| 192.168.31.11
span.center.logo
span.logo
span.logo-baseline
span.right.time
| 13:37
// Modules
ul
each val in modules
li= val
block scripts
script(src="/public/assets/bower_components/jquery/dist/jquery.min.js")
script(src="/public/assets/lib/jquery-taphold/taphold.js")
script(src="/public/assets/lib/background-check/background-check.min.js")
script(src="/public/assets/bower_components/masonry/dist/masonry.pkgd.min.js")
script(src="/public/assets/js/app.js")
And the modules/weather/index.js
var express = require('express');
var app = module.exports = express();
app.get('/', function(req,res){
res.render(__dirname + '/views/sticks.jade');
});
I think the purpose would be like getting the result of the app.get('/') of modules/weather/index.js, but without calling the route, to after insert the result of the rendering into the main view, but I don't know how to do that keeping the modularity of my code...
First, pass your main app to your modules, don't create 2 express apps, you can handle the rest using routes.
You should create a small API and use AJAX calls to fill up your main view :
On the server side :
app.get('/weather', function(req,res){
res.render(__dirname + '/views/sticks.jade');
});
Client jade:
div#weather
Client JS (using jQuery):
$.ajax({ url: '/weather',
type: 'get',
success: function(view) {
$('#weather').html(view);
}
});
#xShirase
First, pass your main app to your modules, don't create 2 express apps
As far as I know, modules in node are cached, meaning, that when you require express in sub-files, you actually get exactly the same instance as in the main app.js/server.js. So passing app doesn't improve anything, but imo makes it a tiny bit uglier.