Route function appears to not be detected - javascript

I'm using a MVC pattern, structuring everything in that style.
Server.js call a routes.js file which is a list of all possible routes. From there I want to call the controller functions to respond to that request.
I am getting getting a 404 error when trying to use a function from the user controller.
Server started on port 3000
MongoDB Connected...
GET /signUp 404 28.578 ms - 37
Server.js
//expose
module.exports = app;
// Bootstrap models //
fs.readdirSync(models)
.filter(file => ~file.search(/^[^.].*\.js$/))
.forEach(file => require(join(models, file)));
// Bootstrap routes //
require('./config/passport')(passport);
require('./config/express')(app, passport);
app.use('/', routes);
routes.js
const express = require('express');
const router = express.Router();
// Controllers //
const Users = require('../../app/controllers/users');
// Other routes //
const index = require('./landing');
//Access to routes
router.use('/', index);
// USER ROUTES //
router.post('/signUp', Users.signUp);
module.exports = router;
users.js
// #route POST signUp
// #desc SignUp/ Register user
// #access Public
const signUp = async (req, res) => {
[
//some checks
];
try{ //some code
} catch(err) {
//error handling
}
It seem that it's due to the controller function, I've tried changing the way I declare the route, but this is the way that makes the most sense to me.
I've started from this "boilerplate", but I don't get the way the routing works. So I changed it to be this way.
What am I doing wrong?
EDIT
As pointed out by #GavinGavin in the comments, the 404 error I'm getting does not match the router.post bit.
So I've went and tried with Postman, It seems to detected the route since I get a 500 server error now. However, in the browser I'm still getting a 404 request.
POST /signUp 500 60.652 ms - 73 //when I try with postman
GET /signUp 404 36.685 ms - 37 //when I refresh the browser

Related

Express.js doesn't redirect to custom URL scheme

I'm currently trying to redirect the user to a custom URL scheme with Express.js to open an app installed on my iPad (using "example://").
Here's my code that should redirect to the URL when a button gets pressed on a page running on a different server:
const { response } = require('express');
const express = require('express');
const router = express.Router();
const path = require('path');
const smartMirror = express();
router.get('/', function(req, res){
res.sendFile(path.join(__dirname + '/test.html'));
});
smartMirror.use('/', router);
smartMirror.listen(process.env.port || 8000);
console.log('Running on Port 8000');
smartMirror.get("/launch", (req, res) => {
res.redirect(302, "touchpoint://");
res.status(200);
})
In the console the error says "UnhandledPromiseRejectionWarning: TypeError: node-fetch cannot load [object Request]. URL scheme "touchpoint" is not supported."
What's the problem here?
You've misidentified the problem. It hasn't go anything to do with Express telling the client it has been redirected, it is because you are trying to access the URL with fetch.
Whatever application touchpoint:// has been registered to be handled with, you need to navigate to the URL.
fetch("touchpoint://") won't work (and this is what you are doing, just via a redirect).
This is for much the same reason that <img src="touchpoint://"> wouldn't work if you tried that.
You need to actually navigate to it. e.g.
<a href="touchpoint://"> or location = "touchpoint://".

Why is Express redirecting infinitely redirecting me?

I am trying to setup a multi language website with Express and NodeJs. My problem is I get redirected what it feels like 100 times and my browser is giving me a error that the webpage is not working because it redirected me too many times.
app.js
app.use('/', (req,res,next) => {
res.redirect('/en-US');
next();
});
app.use('/:lang', indexRouter);
app.use('/:lang/users', usersRouter);
index.js (indexRouter)
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
The problem is that this route handler:
app.use('/', (req,res,next) => {
res.redirect('/en-US');
next();
});
will get hit for not only /, but also /en-US. app.use() matches any route handler for which the path is equal to or a subset of the requested path. So, the browser requests "/", you redirect to "/en-US", which then redirects to "/en-US" and so on, an infinite loop.
I don't know the overall URL design of your site to know what the best overall solution is. You can prevent the infinite redirect loop by just changing app.use() to app.get():
app.get('/', (req,res,next) => {
res.redirect('/en-US');
});
But, that will make the redirect only work for GET requests which may or may not be OK. If you want all HTTP verbs to redirect, you could change to app.all():
app.all('/', (req,res,next) => {
res.redirect('/en-US');
});
The important thing to understand here is that app.get(), app.post(), app.all(), etc... all require an exact match for the URL path, whereas app.use() just requires a subset match. This is a little understood aspect of the Express design.
In addition, remove the call to next() after you do res.redirect(). At that point, you've sent the response, you don't want any other request handlers to see the request. You're done with routing.
under your app.js
Try using
app.use('/', router )
How about you try dealing with the '/' route through the app.js directly instead of index.js

App is not defined in google cloud function with express

I'm trying to use google cloud function to make some API calls. When I deploy on google function, the site send me an Error : Function failed on loading user code. Error message: Code in file app.js can't be loaded. Is there a syntax error in your code? Detailed stack trace: ReferenceError: app is not defined
What could be the reason for this?
These are the files:
//app.js
exports.simple = app;
App.js should call the google cloud function that execute the function call "simple"
IMAGE : 1
// server.js
// BASE SETUP
var express = require('express');
var app = express();
const port = 8080;
// ROUTES
var router = express.Router(); // get an instance of router
router.use(function(req, res, next) { // route middleware that will happen on every request
console.log(req.method, req.url); // log each request to the console
next(); // continue doing what we were doing and go to the route
});
app.use('/',require ('./Routers/API/home'));
app.use('/leads',require ('./Routers/API/leads'));
app.use('/people',require ('./Routers/API/people'));
app.use('/companies',require ('./Routers/API/companies'));
app.use('/opportunities',require ('./Routers/API/opportunities'));
app.use('/projects',require ('./Routers/API/projects'));
app.use('/tasks',require ('./Routers/API/tasks'));
app.use('/activities',require ('./Routers/API/activities'));
app.use('/', router); // apply the routes to our application
// START THE SERVER
// ==============================================
app.listen(port);
console.log('Listening ' + port);
module.exports = {app};
Like mentioned on this post, to use express in a Google Cloud Function, you can put your server code inside the main file and set the app variable as the entry point.

Setting correct structure for a node app

Introduction
So far I have three files, one test.js is a file where I have built three functions that work.
But now I am trying to structure using MVC or at least some pattern. So now I router.js and app.js
Question
Should I put my promise functions from test.js in my config.js or server.js or something else, Im just interested in how people would do this and whats the correct way of structuring NodeJS.
server.js
In here start the server and apply the routes to my app
var configure = require('./router');
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
// get an instance of router
var router = express.Router();
configure(router);
app.listen(port);
console.log('Server has started!! ' + port);
// apply the routes to our application
app.use('/', router);
config.js
In here I build my routes
module.exports = function (router) {
// route middleware that will happen on every request
router.use(function (req, res, next) {
// log each request to the console
console.log(req.method, req.url);
// continue doing what we were doing and go to the route
next();
});
// home page route (http://localhost:8080)
router.get('/', function (req, res) {
res.send('im the home page!');
});
// sample route with a route the way we're used to seeing it
router.get('/sample', function (req, res) {
res.send('this is a sample!');
});
// about page route (http://localhost:8080/about)
router.get('/about', function (req, res) {
res.send('im the about page!');
});
// route middleware to validate :name
router.param('name', function (req, res, next, name) {
// do validation on name here
console.log('doing name validations on ' + name);
// once validation is done save the new item in the req
req.name = name;
// go to the next thing
next();
});
// route with parameters (http://localhost:8080/hello/:name)
router.get('/hello/:name', function (req, res) {
res.send('hello ' + req.params.name + '!');
})
// app.route('/login')
// show the form (GET http://localhost:8080/login)
.get('/login', function (req, res) {
res.send('this is the login form');
})
// process the form (POST http://localhost:8080/login)
.post('/login', function (req, res) {
console.log('processing'); // shows on console when post is made
res.send('processing the login form!'); // output on postman
});
};
test.js
In here is a list of functions that are a chain of promises getting data and API Keys
(small function, one of many that feed into each over)
var firstFunction = function () {
return new Promise (function (resolve) {
setTimeout(function () {
app.post('/back-end/test', function (req, res) {
console.log(req.body);
var login = req.body.LoginEmail;
res.send(login);
resolve({
data_login_email: login
});
});
console.error("First done");
}, 2000);
});
};
My recommended structure is to put everything except server.js in lib directory so all your app is lib/ plus server.js - everything else is package.json, dependencies in node_modules (created on npm install, not in the repo), .gitignore, config files for Travis, Circle, Heroku or whatever service you're using, some README.md and things like that.
Now, server.js is just bare minimum that requires lib/app:
const app = require('./lib/app');
and starts the server with something like:
const server = app.listen(app.get('port'), () => {
logger.info('%s listening on port %s', app.get('name'), app.get('port'));
});
server.on('error', (err) => {
logger.error(err.message || err);
process.exit(1);
});
where logger is some higher lever logger like Winston or something like that.
That's it. Now, lib/app.js is minimum code that loads the middleware like body parsers etc., creates the express app and sets the variables for port and name and then uses a router that is exported by lib/routes:
const routes = require('./routes');
// ...
app.use('/', routes);
The lib/app should be enough to use for testing with tools like supertest but it doesn't listen on any port - server.js does. This is important to simplify testing.
The router exported by lib/routes is used for everything and you can start with a single lib/routes.js file and then convert it to lib/routes/index.js plus several files in lib/routes as needed.
The routes only define the actual routes and input validation with a module like e.g. express-validation and register controllers that are exported by lib/controllers - that can start as lib/controllers.js and get converted to lib/controllers/index.js plus lib/controllers/*.js as needed - just like the routes.
Then I would add top level spec or test or tests directory where all of the tests go. The tests can require your lib/app to run the tests on it with no need to listen on actual TCP ports - those will test your routes with actual controllers. Other tests will require lib/util and run some unit tests on your utilities etc. Make sure to use a tool like istanbul or nyc to calculate the test coverage.
The database schemas and data models would go to lib/schemas and lib/models, some utility helpers in lib/util, some config loading code in lib/config etc.
This is quite flexible layout and works pretty well. You can start with just few files:
README.md
LICENSE.md
package.json
server.js
lib/app.js
lib/routes.js
lib/controllers.js
lib/config.js
etc. and easily convert all of the xxx.js file into xxx/index.js with entire folder of smaller xxx/*.js files as needed.
The main difference from your approach is that I recommend exporting routers and using them by higher level routers instead of passing the high level router into lower lever modules that export functions that take routers to work on.
So instead of:
const moreSpecific = require('more-specific');
const moreGeneral = express.Router();
moreSpecific(moreGeneral);
and then in more specific:
module exports = (router) => {
router.use('/abc/xyz', ...);
};
I would recommend exporting a more specific router in a file e.g. routes/abc.js:
const router = express.Router();
router.use('/xyz', ...);
module exports = router;
and then in more general router e.g. in routes/index.js:
const abc = require('abc');
const router = express.Router();
router.use('/abc', abc);
// and export the main router for other modules like app.js to use:
module.exports = router;
to have a route like /abc/xyz.

Express Generator app.use('/login', users) not picking up routes

I used express generator and am confused as to why I cannot use the users.js routes file for my login routes.
I created the POST route below and if I leave it in app.js it works fine. However, if I move it into users.js and try to use
app.use('/login', users)
where users is :
var users = require('./routes/users');
from app.js to reference it, I get errors that there is no post route to /login. Why does this happen ?
app.post('/login', function(req,res) {
var user = req.body.user;
db.User
.authenticate(user.email, user.password)
.then(function (user) {
req.login(user);
res.redirect("/"); // redirect to user profile
});
});
You're mounting a router that handles /login to the path /login.
This results in the URL /login/login.
You probably want to make the inner router handle /.

Categories