GET endpoint returns a 404 - node.js

I am trying to retrieve specific user data from my Postgres DB.
This code, which retrievs all user data works:
app.get("/employees", async (req, res) => {
try {
const allEmployees = await pool.query("SELECT * FROM employees");
res.json(allEmployees.rows);
} catch (err) {
console.error(err.message);
}
});
But this code meant to retrieve one user doesn't. It returns a 404 on Postman.
app.get("/employees/:id", async (req, res) => {
try {
const { id } = req.params;
const oneEmployee = await pool.query("SELECT * FROM employees WHERE emp_id = $1", [
id
]);
res.json(oneEmployee.rows[0]);
} catch (err) {
console.error(err.message);
}
});
I don't seem to figure out what the problem is.

#AnujPancholi an update. I used the node-postgres queries documentation and changed my code as follows:
app.get("/employees/:emp_id", async (req,res) => {
const query = {
// give the query a unique name
name: 'fetch-user',
text: 'SELECT * FROM employees WHERE emp_id = $1'
}
query.values = [req.params.emp_id];
// callback
await pool.query(query, (err, response) => {
if (err) {
console.log(err.stack);
} else {
res.json(response.rows);
}
});
});
then on Postman my endpoint to a GET route
http://localhost:3000/employees/4
I did not enter any values on the params section. Thanks for pointing me in the right direction, especially on the Postman part.

Related

How to store redis.get value to a variable

I'm trying to store Redis key value to a variable in nodejs, something like
let gPost;
redis.get("posts", async function (err, post) {
if (err) console.log(err);
if (post) gPost = post;
}
but this approach is giving me undefined. Is there any way by which I can store value to Redis? I've already searched for it and a few posts suggested using callbacks. But what I basically want is something like this:
router.post("/:id/likes", async (req, res) => {
try {
redis.get(`posts.${req.params.id}.likes`, function (err, likeCount) {
if (err) console.error(err.message);
redis.get(`posts.${req.params.id}`, async function (err, post) {
if (err) console.log(err);
if (post) {
await customCallback(likeCount, post, req, res);
const retPost = JSON.parse(post);
return res.send({ retPost, redis: true });
} else {
try {
const reqPost = await Post.findById(req.params.id).lean().exec();
redis.set(`posts.${req.params.id}`, JSON.stringify(reqPost));
await customCallback(likeCount, reqPost, req, res);
const retPost = JSON.parse(post);
return res.send({ retPost, redis: false });
} catch (err) {
console.log(err);
}
}
});
console.log(upPost);
});
} catch (err) {
return res.status(500).send({ message: err.message });
}
});
So, here I want to increase my likes count on a post. But I don't want to hit any unnecessary requests to the database. Here first I'm getting posts.id.likes and inside it, I'm trying to fetch that post. If a post is found I'll increase my likes there only. Else, I'll make an API call to the database to fetch that post. Can you where I'm getting it wrong, or any other efficient approach I can use? Thanks.
If you're using a recent version of node-redis, you can just use promises.
Your code seems to simplify to something like
/**
* Get a post from Redis or the database.
*
* If found in the database, caches it in Redis.
*
* Returns a pair: post object and whether it was from Redis.
* #param id Post ID.
*/
async function getPost(id) {
const redisKey = `posts.${id}`;
const postData = await redis.get(redisKey);
if (postData) {
return [JSON.parse(postData), true];
}
const postObj = await Post.findById(id).lean().exec();
await redis.set(redisKey, JSON.stringify(post));
return [postObj, false];
}
router.post("/:id/likes", async (req, res) => {
try {
const { id } = req.params;
const [postObj, fromRedis] = await getPost(id);
const likeCount = await redis.get(`posts.${id}.likes`);
await customCallback(likeCount, postObj, req, res);
return res.send({ postObj, redis: fromRedis });
} catch (err) {
return res.status(500).send({ message: err.message });
}
});

Multiple optional query parameters in Express?

I am using Express and I have a route which makes a GET request to my 'challenges' collection in MongoDB. This will find a specific challenge based on the section number and challenge number.
My code is as follows:
// #route GET api/challenge?section=_&challenge=_
// #description Get challenge by section number and challenge number
// #access Private
router.get('/', auth, async (req, res) => {
try {
const challenge = await Challenge.find({
section_no: req.query.section,
challenge_no : req.query.challenge,
});
if (!challenge) {
return res.status(400).json({ msg: 'Challenge not found' });
}
return res.json(challenge);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
Now this works fine when querying it on Postman. When I enter both query param values 'section' & 'challenge' I get the desired result and it is able to return that particular challenge data.
But my question is:
How can I modify this code so that I can optionally query ONLY section OR BOTH section & challenge. So for example, if I was to query the following:
api/challenge?section=1
It would return all data on all challenges in section 1
But I still want to be able to return a specific challenge by using the query:
api/challenge?section=1&challenge=1
And it would return all data on the first challenge in section 1
Thank you in advance!
You can create a filter object where you put your query strings if exists here is what the code looks like:
router.get('/', auth, async (req, res) => {
try {
const filter = {};
if (req.query.section) filter.section_no = req.query.section;
if (req.query.challenge) filter.challenge_no = req.query.challenge;
const challenge = await Challenge.find(filter);
if (!challenge) {
return res.status(400).json({ msg: 'Challenge not found' });
}
return res.json(challenge);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
One alternative is to use the spread operator, since the keys are the same as database query:
router.get('/', auth, async (req, res) => {
try {
const challenge = await Challenge.find({
...req.query,
});
if (!challenge) {
return res.status(400).json({ msg: 'Challenge not found' });
}
return res.json(challenge);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
In this case, note that query should have the keys "challenge_no" and "section_no" or, the inverse, query should support "challenge" and "section" keys from the query object.

nodejs express postgresql create use in db user table

What is a practical way to check if a user is already in the db before trying to insert the information for a "new user"
Here is my get user by id and insert function:
const getUserById = (request, response) => {
const id = parseInt(request.params.attuid)
pg.query('SELECT * FROM geodate.users WHERE attuid = $1', [attuid], (err, res) => {
if (err) {
return next(err)
}
response.status(200).json(results.rows)
})
}
const createUser = (request, response) => {
const attuid = request.body[0].attuid
pg.query('INSERT INTO geodata.users (attuid, num_queries,created_date,modified_date) VALUES ($1,$2,$3,$4) RETURNING *', [attuid, 0, moment(new Date()), moment(new Date())], (error, results) => {
if (error) {
throw error
}
response.status(201).send(`User added with ID: ${results.rows[0].attuid}`)
})
}
Thanks
rf guy,
Nice shades. First select the user from the geodata.users table. If the user exists, you should not add the user. I don't use pg to query postgres, so I really don't know how it works, but you should be able to do this:
const createUser = (request, response) => { const attuid = request.body[0].attuid
pg.query('SELECT * FROM geodate.users WHERE attuid = $1', [attuid], (err, res)=> {
if (err) {
return next(err)
}
if(results.rows > 0)
{
pg.query('INSERT INTO geodata.users (attuid, num_queries,created_date,modified_date) VALUES ($1,$2,$3,$4) RETURNING
*', [attuid, 0, moment(new Date()), moment(new Date())], (error, results) => {
if (error) {
throw error
}
response.status(201).send(`User added with ID: ${results.rows[0].attuid}`)
})
}
else{
response.status(200).json({"message": "Ha! you are already in the db, silly"})
} }) }

Route returning empty array even though inserting into db seems to be working

I'm learning how to use Sqlite3 with Node, and I'm running into a strange issue. In componentWillMount() on my react front end's main App.js, I make an axios request to the route /all so I can populate a contact list.
What's weird is that, when I hit my other route, /add with a different axios request when I add a contact, it reaches my then() as such,
axios
.post('/add', contactData)
.then(res =>
console.log(`Contact ${contactData.name} added successfully`)
)
.catch(err => console.log('Error encountered: ', err));
With a slight delay too, because I setState before making my axios request, which makes me think that the contact is added into the contacts table.
But when I access localhost:5000/all directly, I receive an empty array [] as the response. I'm not sure what's going on.
Here's my server.js
const express = require('express');
const sqlite3 = require('sqlite3');
const path = require('path');
const cors = require('cors');
const dbName = 'my.db';
const tableName = 'Contacts';
const dbPath = path.resolve(__dirname, dbName);
const app = express();
const port = process.env.PORT || 5000;
app.use(cors());
app.listen(port, () => console.log(`Server running on port ${port}`));
app.get('/all', (req, res) => {
let db = new sqlite3.Database(dbPath);
let sql = `SELECT number FROM ${tableName}`;
db.run(
`CREATE TABLE IF NOT EXISTS ${tableName}(name text, number text, address text)`
);
db.all(sql, [], (err, rows) => {
if (err) {
return res.status(500).json(err);
} else {
return res.json(rows);
}
});
});
app.post('/add', (req, res) => {
let db = new sqlite3.Database(dbPath);
db.run(
`INSERT INTO ${tableName}(name, number, address) VALUES(${req.name},${
req.number
},${req.address})`,
[],
err => {
if (err) return res.status(500).json(err);
}
);
return res.json({ msg: 'success' });
});
Edit:
I should note that when I navigate to /all I get this,
and when I try to post to /add, I get the error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
No where am I sending multiple responses though.
I would not init your db and create your table every time you hit /all.
Try this:
// get this out of the `/all` route, no need to initialize the db object over and over again
let db = new sqlite3.Database(dbPath);
// also leave this outside the `/all` route:
// no need to create the table over and over again.
db.run(
`CREATE TABLE IF NOT EXISTS ${tableName}(name text, number text, address text)`
);
app.get('/all', (req, res) => {
let sql = `SELECT number FROM ${tableName}`;
// according to the sqlite3 api, the second parameter is optional, so just leave it out:
db.all(sql, (err, rows) => {
if (err) return res.status(500).json(err); // if you use return, you don't need 'else' because the code will never reach it.
res.json(rows)
});
});
Your /add route also looks a bit off. Try this:
app.post('/add', (req, res) => {
// let db = new sqlite3.Database(dbPath); // remove this as you already defined it at the beginning of your code.
db.run(
`INSERT INTO ${tableName}(name, number, address) VALUES(${req.name},${req.number},${req.address})`,
err => {
if (err) return res.status(500).json(err);
res.json({ msg: 'success' }); // put the success in the callback (after the query is run!), else, when you get an error, express.js will try to send an error message AND a success message giving you the error "Can't send headers after they are sent"
}
);
});
You can fix this issue Using Async-Await in Node.js.
JavaScript is asynchronous in nature and so is Node. Asynchronous programming is a design pattern which ensures the non-blocking code execution.
The non-blocking code does not prevent the execution of a piece of code. In general, if we execute in Synchronous manner i.e one after another we unnecessarily stop the execution of those codes which is not depended on the one you are executing.
Asynchronous does exactly opposite, the asynchronous code executes without having any dependency and no order. This improves system efficiency and throughput.
But in some case, we need to wait for the response.
app.get('/all',async (req, res) => {
let db = new sqlite3.Database(dbPath);
let sql = `SELECT number FROM ${tableName}`;
await db.run(
`CREATE TABLE IF NOT EXISTS ${tableName}(name text, number text, address text)`
);
await db.all(sql, [], (err, rows) => {
if (err) {
return res.status(500).json(err);
} else {
return res.json(rows);
}
});
});
app.post('/add',async (req, res) => {
let db = new sqlite3.Database(dbPath);
await db.run(
`INSERT INTO ${tableName}(name, number, address) VALUES(${req.name},${
req.number
},${req.address})`,
[],
err => {
if (err) return res.status(500).json(err);
}
);
return res.json({ msg: 'success' });
})
await db.all(sql, [], async (err, rows) => {
if (err) {
await return res.status(500).json(err);
} else {
await return res.json(rows);
}
});

My postman is giving sending request and doing nothing for some values

This is my code in Node JS and I was using mysql
router.post('/districts', (req, res) => {
const stateid = req.body.stateid;
db.query("select id, name from lkup_district where stateid = '"+stateid+"' ", (error, rows) => {
if(error) {
console.log(error);
}
if(rows.length>0) {
res.send(rows);
}
});
});
Using stateid I am getting the districts data. But if I send some stateid which was not present in lkup_districts, Postman is giving me loading and nothing happens. What's going wrong?
Should I write
if(rows.length=0) {
}
Look. You send answer on request only if you find something. If errors occurred or your request find nothing you do not send any data back. So, IMHO, you need to slightly modify your code. Something like
router.post('/districts', (req, res) => {
const stateid = req.body.stateid;
db.query(
"select id, name from lkup_district where stateid = ? "
,[stateid], (error, rows) => {
if(error) {
console.log(error);
res.status(500).send("Error proceeding query");
}
if(rows.length>0) {
res.send(rows);
}
else {
res.status(404).send("No data found");
}
}
);
});

Resources