express.js mongdb its showing data for the wrong call - node.js

I am trying to get data from data base for a certain creator or user, but it shows data even if the creator doesn't exists.
this is the code
app.use('/api/places', placesRoutes);
router.get('/user/:uid', placesControllers.getPlacesByUserId);
const getPlacesByUserId = async(req, res, next) => {
console.log("request data!", req.params.uid);
const userId = req.params.uid;
let places;
try {
places = await Place.find({ creater: userId });
} catch (err) {
const error = new HttpError('Something went wrong, could not find a place for the given user.',500);
return next(error);
}
if(!places || places.length === 0){
return next(new HttpError('Could not find a place for the provided userid.',404));
}
res.json({ places: places.map( place => place.toObject({ getters: true }) ) });
};
this the data entry saved in mondo db
{"_id":{"$oid":"62ab10baa6f33b1c588dfb8e"},"title":"ifel tower","description":"big tower","image":"https://pixabay.com/images/search/nature/","address":"Circular Rd, Walled City of Lahore, Lahore, Punjab 54000, Pakistan","location":{"lat":{"$numberDouble":"31.5924979"},"lng":{"$numberDouble":"74.3073198"}},"creator":"u1","__v":{"$numberInt":"0"}}
it should only show data on this url
api/places/user/u1
but it show the same data on different creator id's
data with different url

I think it's related to the typo in the following line:
places = await Place.find({ creater: userId });
I guess creater should be creator instead.

Related

TypeError: validator.escape is not a function - (express-validator#6.12.1 package)

Codecademy video: link
Explanation:
As part of my Codecademy Back-End Engineer training, I have to do a project outside of their platform. The goal of this project is to make sure a node application is protected from common web attacks.
One challenge I faced was securing the code from Cross-Site Scripting (XSS) attacks. To do this, I used a package called express-validator#6.12.1. The code uses a function called validator.escape which is supposed to protect against any malicious code being inserted into an input form. However, I am getting an error in the console when I try to use it.
Terminal output :
TypeError: validator.escape is not a function
Here is the code :
const validator = require("express-validator");
app.post("/public_forum", function (request, response) {
if (request.session.loggedin) {
var comment = validator.escape(request.body.comment);
var username = request.session.username;
if (comment) {
db.all(
`INSERT INTO public_forum (username,message) VALUES ('${username}','${comment}')`,
(err, rows) => {
console.log(err);
}
);
db.all(`SELECT username,message FROM public_forum`, (err, rows) => {
console.log(rows);
console.log(err);
response.render("forum", { rows });
});
} else {
db.all(`SELECT username,message FROM public_forum`, (err, rows) => {
console.log(rows);
console.log(err);
response.render("forum", { rows });
});
}
comment = "";
} else {
response.redirect("/");
}
comment = "";
//response.end();
});
In the video of Codecademy, the guy uses this function.
Try with:
const {check, validationResult} = require('express-validator');
app.post('/public_forum', async function (request, response) {
if (request.session.loggedin) {
await check('comment').trim().escape().run(req);
const validationResult = await validationResult(req);
if (validationResult.isEmpty()) {
// Good to go...
const { comment } = req.body;
}
...
Link to official docs
I have implemented your code. I tried to add both a malicious and safe comment, but I got an error message on my browser that said, "Port 4000 Not Found." Every time I run the code, it kills the port. So I have implemented another code that works well based on what you sent me.
// This code defines a post request handler for the "/public_forum" endpoint.
app.post('/public_forum', async function (request, response) {
// Check if the user is logged in by checking the session data.
if (request.session.loggedin) {
// Trim and escape the incoming comment.
await check('comment').trim().escape().run(request);
// Get the validation result of the incoming comment.
const errors = validationResult(request);
// If the validation result contains errors, return a 400 status with the errors in a JSON format.
if (!errors.isEmpty()) {
return response.status(400).json({ errors: errors.array() });
}
// Get the comment from the request body.
const { comment } = request.body;
// If a valid comment exists, insert it into the "public_forum" database table.
if (comment) {
db.run(
`INSERT INTO public_forum (username,message) VALUES (?,?)`, [request.session.username, comment],
(err) => {
// If an error occurs while inserting the comment, log the error.
if (err) {
console.error(err);
}
}
);
}
// Select all the rows from the "public_forum" table.
db.all(`SELECT username,message FROM public_forum`, (err, rows) => {
// If an error occurs while selecting the rows, log the error.
if (err) {
console.error(err);
}
// Log the selected rows.
console.log(rows);
// Render the "forum" template, passing in the selected rows as a parameter.
response.render("forum", { rows });
});
} else {
// If the user is not logged in, redirect them to the homepage.
response.redirect("/");
}
});

Supabase & ExpressJS having issues with errors

I have been playing around with ExpressJS I normally use FastAPI. I can't seem to generate an error using Supabase.
I have this endpoint
app.delete('/api/delete-book/:id', cors(corsOptions), async (req, res) => {
const {data, error} = await supabase
.from('books-express')
.delete()
.match({id: req.params.id})
if (error) {
res.status(400).send({message: `ERROR! ${error.message}`})
}
if (data)
res.send({
message: `Book ID ${req.params.id} has been deleted from the database`,
})
})
This works when it comes to deleting a book via an ID. However if I enter an invalid ID I get the data if block firing.
There is no book with an ID of 222 in the database, I would expect the error to fire but its just null
Any ideas here?
This is expected behaviour; not matching any rows is not considered an error condition in postgres.
If you'd like to check if any rows were deleted, you can use something akin to (on supabase-js 2.x):
const { data, error } = await supabase.from('books-express')
.delete()
.match({id: req.params.id})
.select() // not needed on 1.x libs
if (error || data.length === 0) {
res.status(400).send({...})
}

I need to create a rest API in node that calls another API

I need to create a REST API in my node app, that GET data from an external API - https://newsapi.org/v2/top-headlines?category=%7Bcategoryname%7D&apiKey=APIKEY
The condition is that this rest API should contain id of the user in DB.
Only when we trigger an API with valid userID, it should return response as the data coming from external API.
otherwise show error
Can you help me build a function that would do so?
I am using mongoDB
I am writing few snippets of code i wrote to accomplish this, but i am pretty bad at it. So any help on this will be highly appreciated:
app.js
router.get('/api/Users/news/:id', controller.newsget);
router.get('/api/Users/news/:id', (req, res) => {
const id = req.params.id;
for (let i = 0; i <User.length; i++) {
let user = User[i]
if (user.id === id) {
axios
.get('http://newsapi.org/v2/top-headlines?country=in&category=general&apiKey=36f3e29b704f41339af8439dc1228334')
.then(response => {
let userData = response.data;
res.send(userData);})
}
}
});
controller.js
exports.newsget = (req, res)=>{
if(!req.body){
return res
.status(400)
.send({ message : "Data to update can not be empty"})
}
const id = req.params.id;
User.findByIdAndUpdate(id, req.body, { useFindAndModify: false})
.then(data => {
if(!data){
res.status(404).send({ message : `Cannot Update user with ${id}. Maybe user not found!`})
}else{
res.send(data)
}
})
.catch(err =>{
res.status(500).send({ message : "Error Update user information"})
})
}
I have very little clue on the approach, but i badly need assistance. Please help
I have tried mimicking some online functions to search the user and then try to fetch data from external API if the user's ID was present in my DB. But it failed
First of all, you are writing two GET methods for same route, from what I am being concluding that, the first route should be POST according to what I am suspecting to be your functionality is depicted as follows
router.post('/api/Users/news/:id', controller.newsget);
router.get('/api/Users/news/:id', (req, res) => {
const id = req.params.id;
for (let i = 0; i <User.length; i++) {
let user = User[i]
if (user.id === id) {
axios
.get('http://newsapi.org/v2/top-headlines?country=in&category=general&apiKey=36f3e29b704f41339af8439dc1228334')
.then(response => {
let userData = response.data;
res.send(userData);})
}
}
});
Also if you are picking the logged in user, use req.user.id

Express application cannot get certain item from my database (Sqlite)

I am creating an application in which users can create posts and comment on these. Creating, updating and deleting posts works as intended, and so does creating comments.
When the user creates a comment, its accountId is passed to the database.
When deleting a specific comment, the accountId is passed to verify that the user is allowed to delete it.
The problem is, it seems like the accountId isn't fetched from the database, though the query asks for all details from the database table called "comments".
The app is divided into two files, db.js, and app.js.
I have tried modifying the request. In order to troubleshoot, I added a line of code checking if the comment.accountId was fetched, but that is where I get the error.
/* in db.js: */
//get comment by comment id
exports.getCommentById = (id, callback) => {
const query = 'SELECT * FROM comments WHERE id = ?'
const values = [ id ]
db.all(query, values, (error, comment) => {
if (error) {
console.log(error)
callback(['databaseError'])
return
} else if (!comment) {
console.log(error)
callback(['notFound'])
return
} else {
callback([], comment)
}
})
}
/* in app.js */
app.delete('/comments/:commentId', (req, res, next) => {
const commentId = req.params.commentId
db.getCommentById(commentId, (errors, comment) => {
if (errors.length > 0) {
res.status(500).json({
message: 'serverError'
}).end()
return
} else if (!comment) {
res.status(404).json({
message: 'notFound'
}).end()
return
}
const accountId = req.accountId //from my auth middleware
const commAccId = comment.accountId
if(!commAccId) {
console.log(accountId)
console.log(commAccId)
res.status(404).json({
message: 'AccIdNotFound'
}).end()
return
}
- - - - - ^ this is the error checking I inserted, and this is where the error is thrown, so it seems like the id is just not found.
if(!accountId) {
res.status(401).json({
message: 'notAuthenticated'
}).end()
return
} else if (comment.accountId != accountId) {
res.status(401).json({
message: 'notAuthorized'
}).end()
return
}
//plus code for deletion (will insert if it seems relevant, just ask)
})
})
The error message is "AccIdNotFound"
console.log returns 5 (same as the logged in user) and undefined
db.all delivers an array of rows, not just one row. You are assuming the result is a single comment only.
You should check result.length, then pull out result[0].

How do I rewrite a request URL and keep info in same request with express?

I have a REST API for songs resources, they got an id and a title, admins can perform GET /songs/:id directly, but common users can only access through GET /songs/:title.
So if a common user tries to access to a resource like:
{
"id":9248,
"title": "Hala Madrid"
}
By requesting GET /songs/9248 he should be redirected to GET /songs/hala_madrid.
So I could have two different route handlers, and repeat the query. But I really don't want to query twice. So I thought I could reset url and assign the found song to req.song.
I tried setting up the following routes and implement a single get controller method:
router.get('/:id([0-9]+)', songs.get);
router.get('/:title', songs.get);
function get(req, res, next) {
let { id, title} = req.params;
console.log(id, title);
let permalink = id || title;
let field = isNaN(permalink) ? 'title' : 'id';
if (req.song) {
let { song } = req;
return res.render('app', {song, title: 'song', page: 'song'});
}
queries.getSong(field, permalink).then(result => {
let song = result[0];
if (req.session.user.role === 'user' && field === 'id') {
req.song = song;
req.url = `/songs/${song.title}`;
return next();
}
return res.render('app', {song, title: 'song', page: 'song'});
})
.catch(err => {
console.error(err);
return res.status(500).json({error: err});
});
}
I'm a bit lost as it's ending up in unhandled error, I dont know how reload the request to be handled again.
Maybe I'm misunderstanding something but do you have to have two parameters?
router.get('/songs/:idortitle', function(req,res,next) {
const permalink = req.params.idortitle;
const songQuery !isNaN(permalink) && !req.session.user.role ==='user' ? queries.getSong('id',permalink) :queries.getSong('title',permalink);
songQuery.then(result => {
res.render('app', {song, title: 'song', page: 'song'});
}).catch(e => {
console.error(err);
return res.status(500).json({error: err});
});
});
This case just checks if the parameter is a number and the user is not 'user' (then its admin I assume) and then queries by id. Otherwise it queries by title
so /songs/9248 and /songs/hala_madrid works

Resources