I am certain that this is super easy, but I can't for the life of me figure out why this does not work.
So trying to write an application where a user can search, gets a link, and if clocked it calls a second route, passing a variable while it is at it. Sounds simple, so thought I.
The idea is that each link generated gets a link like "localhost:3000/getcan/:[id]"
So for our example, I am trying to get 22 into a variable if I try to go to webpage
"localhost:3000/getcan/:22"
To set up the route, I set the following in app.js
app.use('/getcan/:*', getcan);
This seems to work, and if I put anything that calls /getcan/: I go to the right route.
The route it self looks as follows
var express = require('express');
var router = express.Router();
/* GET getcan page. */
router.get('/', function(req, res, next) {
var canid = req.params.canid;
console.log("Got the following id " + canid)
res.render('getcan', { title: 'ResourceEdge', reqcan: canid });
});
module.exports = router;
I think the problem is with router.get('/' but if I make any changes (tried get('/getcan/:canid) it all blows up with a 404.
Any pointers?
Change app.use to:
app.use('/getcan', getcan);
And your router to:
/* GET getcan page. */
router.get('/:canid', function(req, res, next) {
var canid = req.params.canid;
console.log("Got the following id " + canid)
res.render('getcan', { title: 'ResourceEdge', reqcan: canid });
});
Then call your route using: http://localhost:3000/getcan/22
Related
REST API and Node newbie here. I'm trying to make a REST API in nodejs. Each user would be able to get items associated with their userid and the authentication mechanism is obviously separate from the url. I'm working with something like the following services.
/api/users/userid
/api/users/userid/cars/carid
I expect to have other APIs similar to the 2nd one in the future.
The issue is how to 'bind' the userid and carid or houseid parameters in a clean way. My hope was to be able to have an intermediate step which would capture the 'userid' parameter in the users.js file and then it would delegate the request to the other components. I hoped that this would allow me a more concise authentication checking but there may be more preferable ways. The problem right now is that userid is guaranteed to be unique but carid and houseid are only unique per user so I will need both values to retrieve the data.
My Question is how can I achieve this or is there a better way to organize this to facilitate concise reusable code in terms of authenticating that a user has access to that API. Also if this is very unREST-like, please correct me.
And I have the following code:
app.js
var express = require('express');
var app = express();
app.use('/api', require('./routes/api'));
var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('The server is up at ' + host + ':' + port);
});
./routes/api.js
var express = require('express');
var router = express.Router();
/* GET api listing. */
router.get('/', function(req, res, next) {
res.send('Base of our APIs');
});
router.use('/users', require('./users.js'));
router.use('/', function(req, res) {
res.send('Unauthorized api access. Not authorized for ' + req.baseUrl);
})
module.exports = router;
./routes/users.js
var express = require('express');
var router = express.Router();
router.use('/:user_id/cars', function(req, res, next) {
console.log('Userid is:' + req.params.user_id);
// Authenticate a user here before sending to the next page
var cars_api = require('./cars.js');
cars_api(req, res, next);
});
module.exports = router;
./routes/cars.js
var express = require('express');
var router = express.Router();
/* GET cars for user */
router.get('/', function(req, res, next) {
res.send('Retrieving all cars for user ' + req.params.user_id);
});
router.get('/:car_id', function(req, res, next) {
res.send('Retrieving car with car_id ' + req.params.car_id + ' and user id ' + req.params.user_id);
});
module.exports = router;
I've tried several other ways of calling the cars API that all req.params values are cleared in between. I'm using WebStorm to debug.
You would not necessarily need to write the full route like that, something you might want to look into is nested routes, I think that would help.
Rest with Express.js nested router
here you have a great example I started using when I built my first api.
At the suggestion of commenters, I have decided to just write routes directly to the cars api in the form of /users/:user_id/cars/:car_id.
I have a payment system using node.js and braintree, when the payment is successful I want to send the user to the back end. My back end is setup elsewhere.
I have tried
res.writeHead(301,
{Location: 'http://app.example.io'}
);
res.end();
So window.location is obviously not available. I cant think of any ways to redirect a user?
You can do
res.redirect('https://app.example.io');
Express docs: https://expressjs.com/en/api.html#res.redirect
The selected answer did not work for me. It was redirecting me to: locahost:8080/www.google.com - which is nonsense.
301 Moved Permanently needs to be included with res.status(301) as seen below.
app.get("/where", (req, res) => {
res.status(301).redirect("https://www.google.com")
})
You are in the same situation since your back-end is elsewhere.
app.get("/where", (req, res) => {
res.status(301).redirect("https://www.google.com")
})
You need to include the status (301)
I just have the same issue and got it work by adding "next". I use routers so maybe you have same issue as mine? Without next, i got error about no render engine...weird
var express = require('express');
var router = express.Router();
var debug = require('debug')('node_blog:server');
/* GET home page. */
router.get('/', function(req, res, next) {
debug("index debug");
res.render('index.html', { title: 'Express' });
});
router.post("/", function (req, res, next) {
//var pass = req.body("password");
//var loginx = req.body("login");
//res.render('index.html', { title: 'Express' });
res.redirect("/users")
next
});
module.exports = router;
None of these worked for me, so I tricked the receiving client with the following result:
res.status(200).send('<script>window.location.href="https://your external ref"</script>');
Some will say if noscript is on this does not work, but really which site does not use it.
I have a simple comments app which enables the user to enter a comment into the system via a form and these are then logged onto a list on the bottom of the page.
I wanted to modify it so that a user could click a comments title once it is created and it would load up the associated content that goes with that comment.
I have modified my route in the app.js to lookup the :id:
And have also modified my main Show.js route to use the id as an argument in a findOne command to locate the comment.
I have also put in a console.log() command to log out the req.params.id
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Comment = mongoose.model('Comment', Comment);
router.get('/', function(req, res) {
Comment.findOne({ id: req.params.id }, function(err, comment){
console.log(req.params.id)
});
});
module.exports = router;
However, all I am getting back is an undefined message in my terminal.
If I place the console.log() directly in my app.js, I get the id logged as intended.
app.use('/:id', function(req,res) {
console.log(req.params.id)
});
Am I missing something in my route that is stopping my from getting the id parameter?
You need to specify the :id in your get route, like this:
// GET /1 -> print 1
router.get('/:id', function(req, res) {
console.log(req.params.id);
});
// GET /foo/1/bar/2 -> print 1, print 2
router.get('/foo/:id1/bar/:id2', function(req, res) {
console.log(req.params.id1);
console.log(req.params.id2);
});
You need to pass {mergeParams: true} when calling your router in the router page
var router = express.router({mergeParams: true})
this will pass the parent parameters to the child.
I have a Node js and Express web app.
My app.js looks like
var pages_route = require('./route/pages');
/*
---------------------
------ ROUTE --------
---------------------
*/
app.get('/', pages_route.index);//home
My route/pages.js looks like
exports.index = function(req, res){
res.render( 'home.ejs');
};
I'm trying to pass the view name for every route from the app.js file like the follow:
app.get('/', pages_route.index), template = 'home';
In route/pages.js
exports.index = function(req, res){
res.render( template + '.ejs');
};
This solution works fine for a single route, but when I create more than one like
app.get('/', pages_route.index), template = 'home';
app.get('/custompage', pages_route.custom), template = 'skeleton';
The app will take the last view name passed for all the routes, in this case the view "skeleton" will be printed for all my routes.
I don't want to create a different instance for every route like template1, template2, template3 etc.. I just want to find a solution similar to my example.
Thank you!!
Express doesn't give you just req and res like native node. It also gives you next
Next allows you build middleware, functions that occur as part of handling the request, but don't necessarily end the request.
Here's an example for your use case:
// middleware
function setTemplate (template) {
return function applyTemplate (req, res, next) {
req.template = template;
next();
};
}
// route
app.get('/', setTemplate('home'), pages_route.index);
// handler
exports.index = function (req, res) {
res.render(req.template + '.ejs');
};
I am using parse.com cloud code with express to setup my routes. I have done this in the past with node, and I have my routes in separate files. So, in node I do
app.js
express = require("express");
app = exports.app = express();
require("./routes/js/account");
account.js
app = module.parent.exports.app;
app.get("/api/account/twitter", passport.authenticate("twitter"));
All the examples on parses site https://parse.com/docs/cloud_code_guide#webapp show this being done as follows.
app.js
var express = require('express');
var app = express();
app.get('/hello', function(req, res) {
res.render('hello', { message: 'Congrats, you just set up your app!' });
});
So, I would like to change the bottom to include a routes folder with separate routes files, but am not sure how to do this in parse.
I know this post is a little old, but I just wanted to post a solution for anyone still looking to get this to work.
What you need to do, is create your route file, I keep them in 'routes' forlder, for example <my_app_dir>/cloud/routes/user.js
Inside user.js you will have something that looks like this:
module.exports = function(app) {
app.get("/users/login", function(req, res) {
.. do your custom logic here ..
});
app.get("/users/logout", function(req, res) {
.. do your custom logic here ..
});
}
Then, in app.js you just include your file, but remember that you need to append cloud to the path, and pass the reference to your app instance:
require('cloud/routes/user')(app);
Also, remember that express evaluates routes in order, so you should take that into consideration when importing several route files.
I'm using a different method, have the routes in app.js, but you can probably include them in file if you prefer. Take a look at the example app,
anyblog on github
The way it works:
Set up a controller:
// Controller code in separate files.
var postsController = require('cloud/controllers/posts.js');
Add the controller route
// Show all posts on homepage
app.get('/', postsController.index);
// RESTful routes for the blog post object.
app.get('/posts', postsController.index);
app.get('/posts/new', postsController.new);
And then in posts.js, you can use exports, ex.
var Post = Parse.Object.extend('Post');
// Display all posts.
exports.index = function(req, res) {
var query = new Parse.Query(Post);
query.descending('createdAt');
query.find().then(function(results) {
res.render('posts/index', {
posts: results
});
},
function() {
res.send(500, 'Failed loading posts');
});
};
// Display a form for creating a new post.
exports.new = function(req, res) {
res.render('posts/new', {});
};
Pass the app reference to the post controller, and add the routes from there