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.
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 am creating an MVC structured app. For me this is a new concept. I am having trouble as where to place my middleware. Here's how my app is structured:
Server:
//routes
app.use('/' , userRoutes);
User routes :
//controllers
const postUser = userController.postUser;
const getUser = userController.getUser;
//route
router.route('/user').post(postUser).get(getUser);
And my controllers :
const {check, validationResult } = require('express-validator');
const postUser = (req,res) => {
res.send(req.body);
console.log('POSTED')
};
const getUser = (req,res) => {
res.send(req.body );
console.log('GOTTEM');
};
module.exports = {postUser , getUser};
Where in this bunch should i implement my middleware. I want to use express-validator to check for fields etc, so it has to sit in between the requested path and the callback. Im a bit confused as to where to add my middleware.
It's My Suggestion to use express Boiler Plate for Better MVC Directory Structure and better Routes Understanding.
So after trying some things out myself i've figured it out.
In my routers where i chain all the methods to a specific route:
router.route('/user').post(middleware,postUser).get(getUser);
This worked for me.
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;
I have a problem understanding NodeJS require().
Basically I have this 3 files:
moongooseconfig.js
var config = require('./config');
var mongoose = require('mongoose');
module.exports = function() {
var db = mongoose.connect(config.db);
require('../app/models/user.server.model');
return db;
}
usercontroller.js
var User = require('mongoose').model('User');
exports.create = function(req, res, next) {
var user = new User(req.body);
user.save(function(err) {
if(err) {
return next(err);
} else {
res.json(user);
}
});
};
And the server.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var mongoose = require('./config/mongooseconfig');
var express = require('./config/express');
var db = mongoose();
var app = express();
app.listen(3000);
My understanding of require was that the required module is only visible in the JS file which required the module.
I do not get why the user controller can use the mongoose Model 'User' without requiring the model file.
Yet the mongooseconfig requires the model file inside a function without saving it to a variable.
Can somebody tell me what happens there? Can every file access modules once they where required anywhere?
(Maybe I 'm just to blind, but I can not find the answer in the Node docs and googling "nodejs require scope" does not gave me any good results)
Comments to answer:
mongoose keeps a reference to each of its models. require is just regular JavaScript; it returns an object, and that object has no unusual restrictions on it. The require in mongooseconfig.js is still necessary, though; without it, app/models/user.server.model[.js] will never run and register a model with mongoose.
Say i have this code to separate routes in expressjs:
module.exports = function(express,app,client) {
app.get('/', function(req,res,next) {
var query = 'SELECT * FROM users LIMIT 10';
var user = client.query(query, function (err, results, fields) {
res.render('index', {
title: 'test',
users: results
});
client.end();
});
});
}
And require it in app.js:
require('./controllers/routes.js')(express,app,client);
1) How do i separate db queries into new files in the best way?
This file would get pretty big even if i separate db logic.
2) What is a good way to separate routes? Maybe separate modules? and then require them all in app.js?
There is a similar question here which you should read: How to structure a express.js application?
1) All your query logic should be put in models (modules that reside in /models for example)
2) Separate all your routes (controllers) into modules (and put them in /routes for ex)
By routes I mean for example:
- all the logic for "Users" routes go into /routes/users.js
Try to keep you app as MVC-ish as possible.
Small example for your app above:
app.js
// configuration for express etc
require('./routes/index')(app)
routes/index.js
var model = require("../models/users.js");
module.exports = function (app) {
app.get('/', function (req, res, next) {
model.get_recent(function (err, results) {
// do stuff with your results
res.render('index');
});
});
}
models/users.js
module.exports = {
get_recent: function(callback) {
var query = "SELECT * FROM users LIMIT 10";
database.query(query, callback);
}
}
In the expressjs download package, there is a folder called "mvc". The author provides a good example for a tiny&efficient mvc structure. Going through the code, you will get much inspiration.
How about express-train ? i have been using it lately, and it plays well with complex app structures.