Why is req.params returning undefined? - javascript

I've checked two similar questions here and neither of the things suggested in the comments are working for me.
app.get('/:id', function(req,res) {
console.log(req.params.id);
});
app.get('/:id', function(req, res) {
db.query("SELECT * FROM entries WHERE id = $1", [req.params.id], function(err, dbRes) {
if (!err) {
res.render('show', { entry: dbRes.rows[0] });
}
});
});
As you can see, I've tried logging the result to the console to see what's going on. Visiting the URL in question just makes the page load until it times out. In the console, I get "undefined".
How do I define req.params? Or where is it's definition being pulled and why isn't it returning the values?
Full context: http://pastebin.com/DhWrPvjP

Just tested your code and it works fine. I think you might be missing your url parameter. It should be http://localhost:3000/1 - or whatever ID you're trying to retrieve. Try it out.
Also, you should pass the extended option to your bodyParser.urlencode method: express throws error as `body-parser deprecated undefined extended`
Edit: To specifically answer your question about defining request parameters. You don't have to do anything to define request parameters other than make sure that you're passing in the correct URL. Express takes care of parsing the URL and defining the request parameters for you. So, if you go to the URL http://localhost/jimbob on your server then the value passed in for the id parameter will be available as req.params.id. See this link on request parameters for more info.
Edit 2: You could try debugging your app to see what you get. Here's a link on how to enable debugging in Express and how to use node-inspector for debugging. I saw that your running this on Ubuntu. So, there may be something weird there that I'm not aware of. (I'm running it on a Mac.)
I would also check the version of Node that you're running on the computer(s) that the app works on and check the version of Node on your Ubuntu environment (or whatever computers the app doesn't work on).

app.get('/:id', function(req, res) {
db.query("SELECT * FROM entries WHERE id = $1", [req.params.id], function(err, dbRes) {
if (!err) {
res.render('show', { entry: dbRes.rows[0] });
}
});
});
in your code the url would be localhost/some-id req.params.id would equal some-id, params are pulls straight from the url string, if you are trying to send info with post or get methods you want to use req.body and req.query respectively. I dont see any reason you wouldnt be able to get the id unless the url is wrong
or if you need to do it manually
app.get('/:id', function(req, res) {
//if no req.params and assuming the id is the last item in the url
var urlArray = req.url.split('/'),
id = urlArray[urlArray.length-1];
db.query("SELECT * FROM entries WHERE id = $1", [req.params.id], function(err, dbRes) {
if (!err) {
res.render('show', { entry: dbRes.rows[0] });
}
});
});

try this req.param('id') :D. It may be working for you

I know I'm late to the party but this post helped me debug my issue so I figured I'll add my suggestion in hopes it will help someone else.
If you are using mysql2 with promises
const mysql = require("mysql2");
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE
});
module.exports = pool.promise();
Then you need to use promises in your request.
router.get("/:id", (req, res) => {
mysql
.execute("SELECT * FROM entries WHERE id = $1", [req.params.id])
.then(result => {
res.send(result[0]);
})
.catch(err => {
console.log(err);
});
});
I spent hours debugging my code only to realize I was using promise() in my connection. Hope this helps as this post helped me debug.

Related

Node.js and express (MySQL): Cannot POST / and 404 code in browser

I'm just learning how to make a simple web-application for my dorm that would assign each participant a random number once they enter their name. There is a form field with one text box and a button. The text box (form) needs to send the full name (a single string) to the MySQL database so that later on I could retrieve the full list with the assigned numbers to actually use the application in the real world. Just for redundancy, I've put in code that creates a new database and a table every time, but then SQL ignores it if the DB and table already exist.
My fundamental problem is that I can not get data from my form in HTML. I'm using express.js and am trying to retrieve it, then post it into my database via the SQL module. Now as I'm a complete newbie, I have no idea how it should work. For the past 4 days, I've searched all over the internet to try to solve this issue. I don't know if the js document is the problem or the HTML document.
This is my HTML form (do tell me if you would need the whole thing):
<form action="/createPerson" method="POST">
<input type="text" name="name" value="Ime in priimek">
<input type="submit" name="name" value="Potrdi" class="gumbek">
</form>
And here is my complete node.js document:
var mysql = require('mysql');
var express = require("express");
var bodyParser = require("body-parser");
var urlencodedParser = bodyParser.urlencoded({
extended: false
});
const http = require('http');
var fs = require('fs');
const app = express();
const path = require('path');
const router = express.Router();
// Unique random number generator module
const uniqueRandom = require('unique-random');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
server = http.createServer(app);
server.listen();
// Start connecting to MySQL database
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "root",
database: "mydb"
});
//if database mydb exists, ignore database creation
let createMydb = "CREATE DATABASE if not exists mydb"
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
con.query(createMydb, function(err, result) {
if (err) throw err, console.log("Database already exists!");
console.log("Database OK (Already exists, will not create new one)");
});
});
//if table person exists, ignore table creation
let createTable = "CREATE TABLE if not exists person (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), number VARCHAR(255))";
var sql = createTable;
con.query(sql, function(err, result) {
if (err) throw err, console.log("Table exists, will not create new table");
console.log("Table OK (Already exists, will not create new one)");
console.log('Running at Port 3000');
console.log("Connected. Commencing value input into database.");
//var post = { name: req.body.name, number: random }
//app.get('/createPerson', urlencodedParser, function(err, req, res) {
if (err) throw err;
//res(req.body.name)
});
router.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
//__dirname : It will resolve to your project folder.
});
/*const random = uniqueRandom(1, 100);
const values = ['/createPerson', String(random())];
var insert = "INSERT INTO person (name, number) VALUES (?)"
con.query(insert, [values], function(err, result) {
if (err) throw err;
console.log("Value was inserted into database.");
});*/
app.get('/createPerson', function(req, res) {
res.render('form'); // if jade
// You should use one of line depending on type of frontend you are with
res.sendFile(__dirname + '/index.html'); //if html file is root directory
});
app.post('/createPerson', urlencodedParser, function(req, res) {
const random = uniqueRandom(1, 100);
const values = [String(req.body.name), String(random())];
var insert = "INSERT INTO person (name, number) VALUES (?)"
console.log(req.body.name);
con.query(insert, [values], function(err, result) {
if (err) throw err;
console.log("Value was inserted into database.");
res.sendFile(__dirname + '/numberAssigned.html');
res.end();
});
});
Now every time I press the button in the form, I get Cannot POST /createPerson inside the browser and no data was sent to my database. Browser (network tab) also gives me 404. Maybe it can't find the form?
I am a complete newbie at all of this, I can manage HTML and CSS, Javascript is something really new to me. If you find the time to help me, THANK YOU FROM THE BOTTOM OF MY HEART!
The problem is that you are using node.js http module and express at the same time.
You are setting up /createPerson within the express.js app, but starting the node.js http server instead. So, no end-points are present in the server you've started - hence 404 Page Not Found.
Usually, you use just one of them. Node.js http module provides an ability to start a low-level HTTP server. Express, on the other hand, is a more high-level solution for building http services. So in your case, I would stick with express and throw out http (express is using http module under the hood anyways).
But the fundamental problem of your solution is that it is too big and complex to bootstrap from scratch.
It could be really confusing to figure out what is going on in a complex app, since you are trying to do many things at once - express http server + sql database + html forms... Many things can go wrong, so better try a "Hello World" approach instead.
To debug a problem like that, I would downscale the app and try to check every little interaction level by level:
Level 1
Comment out http module usage and every mapping in express except POST for /createPerson
Make sure you run express app.listen() after the end-point setup.
Comment out all database access in /createPerson handler and leave just a log statement like that:
app.post('/createPerson', urlencodedParser, function(req, res) {
console.log(req.body.name);
}
Now run your script with node.js and try to check the POST on /createPerson with curl:
curl --data-urlencode "name=John Doe (Junior)" http://localhost:3000
(make sure you are using the right port)
Check node.js logs - you have to see a name you're sending with curl in there.
When you see the name in logs, Level 1 is complete!
Level 2
Now try to do the same POST, but form an HTML form.
Add a static mapping on /public to node.js.
Run the node.js server.
Open a page with the HTML form and POST it.
Make sure your form is sending data to correct URL and you see the data in node.js logs
Level 3
Only now, when you have data flowing from html to node.js, you can try to extend the system with a database. Reintegrate db access code back into /createPerson and debug the solution.
Good luck with the next levels!

What is the best way to write a .find query in a GET request with mongodb?

I am trying to make a GET request so that it only returns the last item stored in my database. I can get the answer I want in the mongo shell (see below), but I'm at a loss as to how to compose the query in my GET route. I am using ejs templates, so I will also need to pass the response through the res.render as well. I am still kind of new to programming so forgive me if this question isn't as concise as it should be.
My mongo shell query:
Blog.find().sort({_id:-1}).limit(1)
I hope the code below gives you a hint on how to structure your code using express and EJS.
app.get("/", async (req, res) => {
try {
const blogItem = await Blog.find().sort({_id:-1}).limit(1);
// Render the page with the result
res.render("your-page.ejs", { blog: blogItem });
} catch (error) {
// Handle errors here
res.render("500.ejs");
throw error;
}
});

Express JS/ MongoDB Post not working

I started working on a MERN App today and am trying to write a restful api. First I am using mlab to store my mongodb database. I have succesfully connected to this database after creating a user. I can manually create a collection and inject some data into this collection. From my server.js file I can then get the data stored in here.
MongoClient.connect(db_url, (err, database) => {
if (err) return console.log(err);
var collection = database.collection('memories'); // Collection called memories
app.listen(3000, () => {
console.log("Listening on 3000");
});
});
Thats all fine and dandy but I want to take it to the next level. I want to write a CRUD api for the collection Memory. Coming from django, I would like to create my model first. Therefore, in my models/memory.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MemorySchema = new Schema({
name: String,
description: String
});
module.exports = mongoose.model('Memory', MemorySchema);
Then I went ahead and started working on my routes/api/api.js:
let router = require('express').Router();
let Memory = require('../../../models/memories');
router.use(function (req, res, next) {
console.log("Something is happening");
next(); // Request stops at middleware without next()
});
router.route('/memory')
.post(function (req, res) {
let memory = new Memory();
memory.name = req.body.name;
memory.description = req.body.description;
memory.save(function (err) {
if (err) {
res.send(err);
}
res.json({message: 'Memory Created'});
});
})
.get(function (req, res) {
res.json({message: 'First memory'});
});
module.exports = router;
And in my server.js I call this module:
const apiRoutes = require('./routes/api/api');
app.use('/api/', apiRoutes);
However, after testing the post api with postman, it the POST request just takes forever before showing up as Could not get any response. However, the GET request works. What am I missing?
EDIT: So the post function is having trouble saving the model instance...
Try adding results as the first parameter in the callback of the save function, then res.json(results, { message: "Memory Created" }) to see if you are returned anything.
The main difference between the post and the get method is that the post method uses Mongoose, while the get doesn't. If you fail to connect to the database then the response can time out due to memory.save(...) not working as it should. And there are no responses sent outside the callback to save, so if your program never enter it, you will never send a response. The request will time out eventually.
In your model file you register a model on the following line:
module.exports = mongoose.model('Memory', MemorySchema);
Mongoose will then look for data in the memorys collection. If you change it to
module.exports = mongoose.model('Memory', MemorySchema, 'memories');
it will use the memories collection instead. This will make it consistent with the connection-to-db snippet you posted. I don't know if that will fix your issue though. I would suggest changing the connection code to
mongoose.connect(dburl, {
useMongoClient: true
});
instead of the native mongo client. You can add these lines too
mongoose.connection.on('connected', function () {
console.log('Mongoose connected');
});
mongoose.connection.on('error', function (err) {
console.log('Mongoose connection error: ' + err);
});
mongoose.connection.on('disconnected', function () {
console.log('Mongoose disconnected');
});
right after the connection code to help with debugging. Make sure you get connected when starting the app.
If you see an error similar to this Error: Can't set headers after they are sent. in the node terminal window, it might be because you are sending two responses in the post function. If an error occurs while saving it will enter the if(err) block, send a response async then go to the res.json(...) response and send that too.
So you have to return after sending the response to exit the function. Either like this
res.send(err);
return;
or like this
return res.send(err);
Same for the json response.
If that doesn't fix the problem you should either fire up the debugger (node --inspect or nodemon --inspect), or insert a console.log('inside post'); inside the post function to see that you're actually entering it.

How do I make a MongoDB query throw an error if there is no database connection? [duplicate]

I'm new to Mongo. I needed a database for a simple project and ended up following a tutorial using Mongo with Monk but I have problems understanding how to handle errors.
Background: I have a registration form on the client side. When the user clicks a button, the data is sent via AJAX to the controller that (upon validation, but this is not relevant now) inserts such data into the database and sends back either success or error. When the db is up all seems to work fine.
The problem: If I don't start the db and try to send the request anyway, no error is returned. Simply nothing happens. After some time on the console I get: POST /members/addmember - - ms - -.
I think some error should be returned to the user in this case, so how could I do this?
The post request is below (pretty much as from the tutorial):
// app.js
var db = monk('localhost:27017/dbname')
[...]
// I realize it might be not optimal here
app.use(function(req,res,next){
req.db = db;
next();
});
// members.js
router.post('/addmember', function(req, res) {
var db = req.db;
var collection = db.get('memberstest');
collection.insert(req.body, function(err, result){
res.json(
(err === null) ? { msg: 'success' } : { msg: err }
);
});
});
If the db is down I guess the problem is actually even earlier than the insert, that is in that "db.get()". So how to check if that get can actually be done? I suppose that given the asynchronous nature of node something like a try/catch would be pointless here. Correct?
EDIT: After Neil's answer and a bit of trying, I put together the following that seems to do the job. However, given my scarce degree of confidence on this, I'd appreciate a comment if the code below works because it makes sense or by chance. I added the bufferMaxEntries: 0 options and modified the controller as follows. In the ajax callback I simply have an alert for now that shows the error message thrown (if any).
router.post('/addmember', async (req,res) => {
try {
let db = req.db;
let collection = db.get('memberstest');
collection.insert(req.body, function(err, result){
res.json(
(err === null) ? { msg: 'success' } : { msg: err }
);
});
await db.then(() => 1);
} catch(e) {
res.json({msg: e.message})
}
});
Well you can actually set the bufferMaxEntries option ( documented under Db but deprecated for that object usage, use at "top level as demonstrated instead" ) on the connection, which essentially stops "queuing" requests on the driver when no connection is actually present.
As a minimal example:
index.js
const express = require('express'),
morgan = require('morgan'),
db = require('monk')('localhost/test',{ bufferMaxEntries: 0 }),
app = express();
const routes = require('./routes');
app.use(morgan('combined'));
app.use((req,res,next) => {
req.db = db;
next();
});
app.use('/', routes);
(async function() {
try {
await db.then(() => 1);
let collection = db.get('test');
await collection.remove({});
await collection.insert(Array(5).fill(1).map((e,i) => ({ a: i+1 })));
console.log('inserted test data');
await app.listen(3000,'0.0.0.0');
console.log('App waiting');
} catch(e) {
console.error(e);
}
})();
routes.js
var router = require('express').Router();
router.get('/', async (req,res) => {
try {
let db = req.db,
collection = db.get('test');
let response = await collection.find();
res.json(response);
} catch(e) {
res.status(500).json(e);
}
});
module.exports = router;
So I am actually awaiting the database connection to at least be present on "start up" here, but really only for example since I want to insert some data to actually retrieve. It's not required, but the basic concept is to wait for the Promise to resolve:
await db.then(() => 1);
Kind of trivial, and not really required for your actual code. But I still think it's good practice.
The real test is done by stopping mongod or otherwise making the server unreachable and then issuing a request.
Since we set the connection options to { bufferMaxEntries: 0 } this means that immediately as you attempt to issue a command to the database, the failure will be returned if there is no actual connection present.
Of course when the database becomes available again, you won't get the error and the instructions will happen normally.
Without the option the default is to "en-queue" the operations until a connection is resolved and then the "buffer" is essentially "played".
You can simulate this ( as I did ) by "stopping" the mongod daemon and issuing requests. Then "starting" the daemon and issuing requests. It should simply return the caught error response.
NOTE: Not required, but in fact the whole purpose of async/await syntax is to make things like try..catch valid again, since you can actually scope as blocks rather than using Promise.catch() or err callback arguments to trap the errors. Same principles apply when either of those structures are actually in use though.

Manage node-postgres query

I've read through node-postgresā€™s API documentation.
It recommended that we use the pg object to create pooled clients. And in pg.connect api documentation said:
The connect method retrieves a Client from the client pool, or if all
pooled clients are busy and the pool is not full, the connect method
will create a new client passing its first argument directly to the
Client constructor.
So according to the recommendation, does using pg.connect mean "using the pg object to create pooled clients"? If it's not, what does it actually mean?
And in my implementation example, I made several queries in my route:
app.get('/post', function(req, res) {
pg.connect(dbconfig, function(err, client, done) {
client.query('SELECT * FROM post', function(err, result) {
res.render('post/list', { posts: result.rows });
});
});
});
app.get('/post/new', function(req, res) {
res.render('post/new');
});
app.post('/api/v1/post', function(req, res) {
var b = req.body;
pg.connect(dbconfig, function(err, client, done) {
client.query('INSERT INTO post (title, content) VALUES ($1, $2)',
[b.title, b.content],
function(err, result) {
done();
res.redirect('/post');
});
});
});
Is it the right way to call pg.connect each time I want to make query? If not, what is the better idea?
It does look, according to the documentation that pg.connect() does handle pooled connections. I would suggest however one thing you could likely do better (assuming you only have one set of credentials your app is using).
If I were looking at doing this, I would work on saving duplication of effort/keystrokes/opportunities for error a bit and look at wrapping pg.connect() in some sort of function you could use that would return client. This would enable you to do something more like:
app.get('/post', function(req, res) {
db.run( function(client) {
client.query('SELECT * FROM post', function(err, result) {
res.render('post/list', { posts: result.rows });
});
});
});
However, given the way you have things done, I am not convinced you have a lot to gain by such an approach, so I don't see anything wrong with your approach.
This might be a little outdated now, but take a look at this:
https://github.com/aichholzer/Bodega
It will take care of any worries and make your coding experience a little more pleasant.
:)

Categories