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.
Related
I'm creating a Next.js Frontend - Express.js Backend Web App.
I have some problems with routing. In the official documentation of Next.js, I read that if we use a custom server, we have to disable the automatic routing that uses the folder /pages to work.
module.exports = {
useFileSystemPublicRoutes: false,
}
But at this point, how can I route the pages. I'm thinking to still use the /pages folder to group the several pages.
How can i route from backend? Have I to import in some way the javascript
pages? Like this code...
router.get('/users', function (req, res) { "import Next.js page" });
Or it's antoher type of process like use "react-router".
Can anyone give me an example of the best choice? Thanks
You can use next-routes.
// server.js
const next = require('next')
const routes = require('./routes')
const app = next({dev: process.env.NODE_ENV !== 'production'})
const handler = routes.getRequestHandler(app)
// With express
const express = require('express')
app.prepare().then(() => {
express().use(handler).listen(3000)
})
// Without express
const {createServer} = require('http')
app.prepare().then(() => {
createServer(handler).listen(3000)
})
and your routes.js file
const routes = module.exports = require('next-routes')()
routes
.add('about')
.add('blog', '/blog/:slug')
.add('user', '/user/:id', 'profile')
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 trying to import route logic from another file. In express js this is achievable via express.Route(), when i tried polka.Route() an error pops up saying Route doesn't exist in polka.
Express Implementation
server.js
const express = require('express');
const users = require('./routes/api/users');
const app = express();
app.use('/users', users);
user.js
const express = require('express');
const router = express.Router();
router.get('/test', (req, res) => res.json({ msg: 'works' }));
module.exports = router;
When /users/test is hit the output is {msg:'works'}. This works for the express implementation. For the polka implementation i changed the word express to polka installing it. The issue arises on the line polka.Router() of user.js. How do i enable this functionality of importing route logic from another file in polka.
The polka micro web server does not implement a difference between routers and the app. In your users.js file simply setup your routes as you would in your server.js file and then module.export. See Below:
Polka Implementation
server.js
const polka = require('polka');
const users = require('./routes/api/users');
const app = polka();
app.use('/users', users);
user.js
const polka = require('polka');
const router = polka();
router.get('/test', (req, res) => res.end(JSON.stringify({ msg: 'works' })));
module.exports = router;
Hope this help!
Also, here is a good link to see other differences between Express.js and Polka.js: https://github.com/lukeed/polka#comparisons
I'm creating a programmer job board app and I'm trying to display json data on my main page. At some point I'll render it, but for now I'm just trying to get it to show up in json form so that I know it works.
I'm able to connect to the server, but when I load the page I get a TypeError (Job.showAllJobs is not a function).
I'm using a crud app I made the other week as a reference, but there are a few differences between it and this project that are throwing me off.
Here's my project's file structure:
job-board
database
connection.js
schema.sql
models
Job.js
User.js
views
index.ejs
login.ejs
server.js
Unlike my previous crud app, this project is using a connection.js file that gave some trouble earlier. At first I thought I was out of the woods, but I think it might be responsible for my current problem.
Not getting GET to work might seem like a minor error, but it's really bugging me and I haven't been able to keep working because of it.
I populated my table (jobs) with a sample listing as a test, but in the very near future I plan on connecting the app to the GitHub jobs api.
server.js:
const express = require('express');
const app = express();
const PORT = 3000;
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const Job = require('./models/Job');
const User = require('./models/User');
const connection = require('./database/connection')
app.use(bodyParser.json())
app.use(methodOverride('_method'));
const urlencodedParser = bodyParser.urlencoded({ extended: false })
app.set("view engine", "ejs");
///// GET /////
// GET INDEX
app.get('/', (request, response) => {
Job.showAllJobs().then(everyJob => {
response.json('index');
// response.render('index', { jobs: everyJob });
});
});
Job.js
const Job = {};
const db = require('../database/connection');
///// JOBS /////
/// INDEX ///
Job.showAllJobs = () => {
return db.any('SELECT * FROM jobs');
};
module.exports = Job;
module.exports = db;
connection.js
// require database setup to use pg-Promise
const pgp = require('pg-promise')({});
// connection url
const connectionURL = "postgres://localhost:5432/job_board";
// new database connection
const db = pgp(connectionURL);
// module.exports = db;
You have a couple of problems here.
Make sure you're passing the jobs into res.json instead of the string 'index'
Make sure you're exporting db from connection.js
You're exporting both Job and db from Job.js. Since you're exporting db second, it's overriding the export of Job.
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.