How to export routes in node.js and express? - javascript

My problem is not in the question totally, but it's in the same page.
So I exported a route to my main app.js file but the my post route isn't working. My problems are below the code because I need you to read the code in order to be clear.
This is my file from where i will export the route(registration.js):
const express = require("express");
const router = express.Router();
console.log("azerty");
router.post("/register", (req, res)=>{
console.log("qwerty");
res.stautus(200).send("hello");
});
module.exports = router;
This is my main file to where i will export the route (app.js):
const express = require("express");
const app = express();
...
app.use("/register", require("./registration.js"));
This is my html form:
<form action="/register" method="post">
<input type="text" placeholder="First Name" name="fstName" required/>
<input type="text" placeholder="Last Name" name="lstName"required/>
<input type="submit" value="Submit"/>
</form>
I have some other issues related to this:
first: why does azerty log to the console when I'm at
http://localhost:3000/?
second: why I keep getting Cannot POST /register and in the developer tool a 404 error? And my code inside the route handler doesn't run.
lastly: Is this the right way to export routes(like using the express.Route() in the routing file and express() only in the main one)?

first: why does azerty log to the console when I'm at http://localhost:3000/?
console.log("azerty") is in file scope of registration.js, so will be logged as soon as your app.js requires it.
This line here is enough to triger the console logging: app.use('/register', require('./registration')); becuase module is required when express mounts it as middleware on start
second: why I keep getting Cannot POST /register and in the developer tool a 404 error? And my code inside the route handler doesn't run.
Becuase it is not mounted where you think it is mounted.
router.post("/register ... Here you've mounted at /register path, and then app.use("/register", require("./registration.js")); here you've mounted to another /register path. Combine the two together, you get full path as /register/register (Also check the typo mentioned in comment)
So to mount at localhost:3000/register, you've to define like (Note the differences):
router.post("/", (req, res)=>{ ...
// and then
app.use("/register", require("./registration.js"));
// or simply
router.post("/register", (req, res)=>{ ...
// and then
app.use(require("./registration.js"));
lastly: Is this the right way to export routes(like using the express.Route() in the routing file and express() only in the main one)?
Yes, it's perfectly fine. But keep in mind the mount path.

I think you added a prefix to the route with app.use("/register"...) and now it is /register/register
Juste remove it in app.js or in your route file
const express = require("express");
const router = express.Router();
console.log("azerty");
router.post("/register", (req, res)=>{
console.log("qwerty");
res.stautus(200).send("hello");
});
module.exports = router;
const express = require("express");
const app = express();
...
app.use(require("./registration.js"));
I don't know if it is the right way here's what i do its kinda like you
//src/app.js
// Import
import postRoutes from './routes/post';
import authRoutes from './routes/auth';
...
// Endpoints
app.use(postRoutes);
app.use(authRoutes);
// src/routes/post.js
...
const Router = express.Router();
/**
* Routes
*/
Router.get('/post', getPosts);
Router.post('/post', isAuth, creationValidation(), createPost);
Router.put('/post/:id', isAuth, editValidation(), putPost);
Router.delete('/post/:id', isAuth, deletePost);
/**
* Export
*/
export default Router;

Firstly, azerty is getting logged because it's not nested inside any functions. It will simply log on runtime and you being at http://localhost:3000/ has no influence on this.
Second, you Cannot POST /register because when using router, the root is the first parameter passed to app.use - in your current setup, /register/register is the route.
To fix this, change the first parameter of router.post in registration.js to just /:
const express = require("express");
const router = express.Router();
console.log("azerty");
router.post("/", (req, res)=>{
console.log("qwerty");
res.status(200).send("hello");
});
module.exports = router;
Finally, for exporting routes this is the most common setup I see.

azerty was logged to the console that means the route was imported and it worked.
You have already exported the route in the right way.
I think you shoud use return before res.stautus(200).send("hello"); in registation.js.
Like that:
const express = require("express");
const router = express.Router();
console.log("azerty");
router.post("/", (req, res)=>{
console.log("qwerty");
return res.stautus(200).send("hello");
});
module.exports = router;
To use this request, the api looks like: localhost:3000/register

Related

Is it possible to use application level middleware in express router?

I've been playing around with setting up a basic atlassian-connect-express (ACE) application, and have modified the starter code provided by the ACE package to be suitable for serverless deployment. One of the problems I faced after doing this was that routing is now divided into stages, e.g. /dev, /prod. I did a bit of research and found that a way to deal with this would be to use an express Router and mount it to the appropriate endpoint for the stage being deployed to. The problem I then faced is that the authentication middleware provided by ACE seems to be application level and then can't be used by each router.
Typically the routes were added to the express app like this:
import ace from 'atlassian-connect-express';
import express from 'express';
import routes from './routes';
const app = express();
const addon = ace(app);
app.use(addon.middleware());
routes(app, addon);
and in ./routes/index.js
export default function routes(app, addon) {
// Redirect root path to /atlassian-connect.json,
// which will be served by atlassian-connect-express.
app.get('/', (req, res) => {
res.redirect('/atlassian-connect.json');
});
// This is an example route used by "generalPages" module (see atlassian-connect.json).
// Verify that the incoming request is authenticated with Atlassian Connect.
app.get('/hello-world', addon.authenticate(), (req, res) => {
// Rendering a template is easy; the render method takes two params:
// name of template and a json object to pass the context in.
res.render('hello-world', {
title: 'Atlassian Connect'
});
});
// Add additional route handlers here...
}
I've changed ./routes/index.js to work as a router object and export that, however this leaves me unable to use the addon.authenticate() middleware
import ace from 'atlassian-connect-express';
import express from 'express';
import routes from './routes';
const app = express();
const addon = ace(app);
app.use('/dev', require('./routes'));
and in ./routes/index.js
const express = require('express');
const router = express.Router();
// Redirect root path to /atlassian-connect.json,
// which will be served by atlassian-connect-express.
router.get('/', (req, res) => {
res.redirect('/atlassian-connect.json');
});
// This is an example route used by "generalPages" module (see atlassian-connect.json).
// Verify that the incoming request is authenticated with Atlassian Connect.
router.get('/hello-world', addon.authenticate(), (req, res) => {
// Rendering a template is easy; the render method takes two params:
// name of template and a json object to pass the context in.
res.render('hello-world', {
title: 'Atlassian Connect'
});
});
module.exports = router;
Obviously having no knowledge of addon, the router cannot use that authentication middleware.
Is it possible to pass that middleware through to the router when attaching it to the application? If not, is there another way I can handle URL prefixes without using a router?

Page renders using router.use but gives a 'Cannot GET. error with router.get

I am new to javascript and node.js I am learning online and trying to create a cms using node.js, express and sqlite. Before going to details I will give you guys my directory structure.
rootdir
node_modules
public
css (generic styling files)
vendor (bootstrap and js files)
routes
defaultRoutes.js
views
default
index.handlebars
partials
default
(header and footer files)
layouts
main.handlebars
app.js
package-lock.json
package.json
app.js is where the server is created and defaultRoutes are for routes. When I run
//code in defaultRoutes.js
const express = require('express');
const router = express.Router();
router.use((req,res) => {
res.render('default/index');
});
module.exports = router;
and
//code in app.js
//Routes
const defaultRoutes = require('./routes/defaultRoutes');
app.use(defaultRoutes);
the page renders but when I change the router.use in defaultRoutes to router.get the browser throws cannot GET error.
Can anyone explain why this is happening?
You need to define a route when using router.get(). router.use() can work for any route, but to define a route with router.get() you can add the route like this:
//code in defaultRoutes.js
const express = require('express');
const router = express.Router();
router.get('/', (req,res) => {
res.render('default/index');
});
module.exports = router;

Appending a Prefix to Routes in One File in Express JS

I am currently refactoring my code and I am hoping there is a more efficient way to make my code look pretty. Here is what I currently have:
router.route('/api/merchant/')
.get(controllerFunction)
.post(controllerFunction);
router.route('/api/user/')
.get(controllerFunction)
.post(controllerFunction);
router.route('/admin/user/')
.get(controllerFunction)
.post(controllerFunction);
router.route('/admin/place/')
.get(controllerFunction)
.post(controllerFunction);
You can see that I have "api" and "admin" as prefixes to certain routes.
I can separate the API route into another file and have the "app.use" middleware append them appropriately, but I was wondering how can I get around this and have these routes in a single file with the main problem being at the end of the file:
module.exports = router
which only allows me to have one prefix to all my routes.
Short answer for your question follow below
You can put your middleware in separate file.
[name]Controller.js
module.exports = (req, res)=>{
res.send('I am a middleware');
}
Create a file bootable routers and export an array from routers.
boot.js
const express = require('express'),
router = express.Router(),
[name]Controller = require('./controller/[name]Controller'),
module.exports = [
router.get('/your path', [name]Controller),
...
]
Use router in your app file.
app.js
const express = require('express'),
boot = require('./boot'),
app = express();
app.use('/prefix', boot);
Now you can use routes with prefix for example:
localhost:3000/prefix/yourpath
You can folow below block code, but I suggest you write controler function to another file each for once.
var router = express.Router();
var useApi = router.route('/user')
.get(controllerFunction)
.post(controllerFunction);
var useAdmin = router.route('/user')
.get(controllerFunction)
.post(controllerFunction);
app.use('/api', userApi);
app.use('/admin', userAdmin);
You can mount the whole router on a path. If you do something like:
router.get('/:id', someFn);
Then elsewhere you could do:
app.use('/api', router);
and the route '/api/:id/` would resolve to the someFn handler
UPDATE
I'm not sure I fully understand your concern, and frankly having all your routes in one file makes for a file longer than I'm comfortable with, but if you really only want to mount one router, you can do something similar to what I described, but inside your routes file.
In that case, you'd still create the multiple routers but then rather than exporting them and mounting on the app, you'd do this:
const adminRouter = express.Router();
// configure the admin routes as I described
const apiRouter = express.Router();
// configure API routes
const main = express.Router();
main.use('/admin', adminRouter);
main.use('/api', apiRouter);
module.exports = main;

Taking routes from server.js to routes.js without passing parameters

I have a server.js on my root folder with the following content.
// server.js
const app = express();
const HomeController = require("./controllers/HomeController");
const UserController = require("./controllers/UserController");
app.use(...)
app.use(...)
app.get('/', HomeController.index);
app.get('/login', UserController.getLogin);
I want to take app.get endpoints in a file called routes.js so it looks like this:
// routes.js
app.get('/', HomeController.index);
app.get('/login', UserController.getLogin);
When I do it, app, HomeController and UserController becomes undefined.
I can pass them to routes.js like so:
require("routes")(app, HomeController, UserController);
However, it is not future compatible so if I ever create a new controller, I must pass them into routes.js file.
Instead, can I somehow tell routes.js to access server.js scope? Is there any way to access variables in server.js via routes.js?
Why you didn't use the default pattern of the ExpressJS. like:
var apiRoutes = require('./api_server/routes/api');
app.use('/api', apiRoutes);
.../routes/api.js:
var express = require('express');
var router = express.Router();
var loginCtrl = require('../controllers/auth/login');
router.post('/authenticate', loginCtrl.login);
router.post('/resetAdminPassword', loginCtrl.resetAdmin);
// router.get('/tieba/:id', tiebaCtrl.one);
module.exports = router;

Access Express app within Express Router

I have an ExpressJS application that uses several routers. Here is the basic form of the main app that ties everything together.
var express = require('express');
var routes = require('./routes/index');
var app = express();
app.set('someKey', someObj);
app.use('/', routes);
module.exports = app;
I have removed most of the code for brevity.
In that ./routes/index.js file I have defined a Express Router in the form:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('index', { title: 'Express Test' });
});
module.exports = router;
I have attempted to use the following to access "somekey" from inside the router:
var app = require('../app');
var foo = app.get('somekey');
This crashes and burns with the runtime informing me that there is no such method get for app (further investigation yields that app is just a default Object).
I assume I am overlooking something that is completely obvious.
I plan to be passing a single knexjs object to each of the routers that deal with database calls. In the code's current state it is duplicated across each of the routers. I'd like to have it defined once in the main app and then be used by all of the routers such that if a change is made in the main app it is reflected across the routers.
When you require the app that way, you are not exactly referring to the app object you defined in your app.js. Instead, you are asking for whatever that file exported. To get what you want to achieve, may use something like this.
In your app.js
var express = require('express');
var app = express(); // Note the switched order
app.set('someKey', someObj);
var routes = require('./routes/index')(app);
app.use('/', routes);
module.exports = app;
Then in your routes:
var express = require('express');
var router = express.Router();
/* Wrap everything inside a function */
module.exports = function(app){
console.log(app.get('someKey')); // Access app passed to it from app.js
/* Declare all your routes here. app variable will be accessible */
router.get('/', function(req, res) {
res.render('index', { title: 'Express Test' });
});
return router;
};
Basically, whenever you are requiring a file B from A and want to pass a variable from A to B, this is the general pattern you follow.
See if if helps. :)

Categories

Resources