I am creating URL Shortener Microservice application.I have a mongodb cluster that i save my all url links. I am successfully connect to database.I am making post request to save my posted url. Related code is here
app.post('/api/shorturl', (req, res) => {
const bodyUrl = req.body.url;
const something = dns.lookup(
urlParser.parse(bodyUrl).hostname,
(error, address) => {
if (!address) {
res.json({ error: 'Invalid URL' });
} else {
const url = new Url({ url: bodyUrl });
url.save((err, data) => {
res.json({
original_url: data.url,
short_url: data.id,
});
});
}
}
);
});
So, I can save my new url in database succesfully.Here also related cluster after post request
But my problem is with get request. I dont know why i cant find the url links by id. Here also my get request
app.get('/api/shorturl/:id', (req, res) => {
// const id = req.body.id;
Url.findById({ _id: req.body.id }, (err, data) => {
if (!data) {
res.json({ error: 'Invalid URL' });
} else {
res.redirect(data.url);
}
});
});
You need to either use:
Url.findOne({ _id: req.params.id }, (err, data) => {
if (!data) {
res.json({ error: 'Invalid URL' });
} else {
res.redirect(data.url);
}
});
or:
Url.findById(req.params.id, (err, data) => {
if (!data) {
res.json({ error: 'Invalid URL' });
} else {
res.redirect(data.url);
}
});
findOne takes an object as the argument (like you have).
findById just takes the ID as the argument.
You seem to be combining the two options.
Edit: I found another issue with your code, you are trying to pull the id from req.body.id, but in this case, you need to use req.params.id. The code in my post has been updated.
Related
I always receive the following error message from NodeJs when trying to get some content via a POST request. <-- This problem is solved.
I would like to get two fields from the database now: name and levels.
Here are the methods:
mongodb (courses):
_id: 12345
teacherId: 9876
userId: 567
name: "admin"
levels: "Advance"
route:
router.get('/course/:userid/showCourses', courseController.showCourseById)
controller:
const showCourseById = async (req, res, next)=>{
try {
let userId = req.params.userId || {};
const course = await courseService.getCourseById(userId);
res.json(course);
} catch (error) {
res.status(500).json({error: error})
}
}
service:
function courseService() {
function getCourseById(userId) {
try {
await courseModel.findById({userId: new ObjectId(userId)}, 'name levels', function(err, items){
if(err) return next(err);
res.send(items);
});
} catch (error) {
console.log(`Course not found. ${error}`)
}
}
return {
getCourseById: getCourseById
}
}
And this is my Postman request
https://xyz/api/course/12345fabe3bd0a386d0962e77
Now, after changing router.post to router.get, I am able to call the method via Postman, however, it returns the login webpage
my backend send a res.staus(200).json({somedata)} to my front, but i can't retrieve the data in the frontend.
My backend :
exports.login = (req, res, next) => {
//===== Check if user exists in DB ======
const { user_email, user_password: clearPassword } = req.body;
let sql = `SELECT user_password, user_id FROM users WHERE user_email=?`;
db.query(sql, [user_email], async (err, results) => {
console.log(results);
console.log(req.body);
if (err) {
return res.status(404).json({ err });
}
// ===== Verify password with hash in DB ======
const { user_password: hashedPassword, user_id } = results[0];
try {
const match = await bcrypt.compare(clearPassword, hashedPassword);
if (match) {
console.log("match ... user_id : ", user_id);
// If match, generate JWT token
res.status(200).json({
test: 'iyu',
user_id: user_id,
token: jwt.sign({ userId: user_id }, "TOOOKEN", {
expiresIn: "24h",
}),
});
} else {
console.log("not match");
}
} catch (err) {
return res.status(400).json({ err: "une erreur" });
}
});
};
The frontend :
const login = async (e) => {
e.preventDefault();
await POST(ENDPOINTS.USER_LOGIN, userLogin);
// await GET(ENDPOINTS.USER_LOGIN)
fetch("http://localhost:4200/api/auth/login")
.then((response) => response.json())
.then((data) => {
console.log(data);
});
};
This login fonction send data to my backend, then the backend checks if an user exist in database with the first POST request. If yes, the backend send in json format some data that i wan't to put in the local storage of the user, so after the POST request, i do another request with GET method to retrieve the json data sent from the back, but i have an 404 error.
How can i get my data sent by the back ?
Seems the problem is with the SQL statement, underneath the if statement you have can you print the error like so:
if(err) {
console.log(err);
}
and tell me the result please
GoodDay Experts,
I've tried following code but it did not work, and it gives me null value.. maybe my routes are wrong but basically it works the way on other routes... and here is my backend for delete case: manage.js/actions
export const removeRecipient = (payload) => async (dispatch) => {
try {
const res = await axios.delete(
`${_config.MAT_URL}/api/1/customer/delete`,
payload
);
dispatch({
type: DELETE_CUSTOMER,
payload: res.data,
});
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { err },
});
}
};
and for my routes which is the mongoose query for findOneAndDelete, under customer.js :
router.delete("/delete", (req, res) => {
Customer.findOneAndDelete({ _id: req.params.id }, (err, Customer) => {
if (!err) {
res.json({ msg: "customer deleted", deleted: Customer });
} else {
console.log("Error removing :" + err);
}
});
});
And for the front end im using "AiOutlineDelete" which was coded as :
const handleDelete = (id) => {
console.log('delete')
removeRecipient(id)
}
<a
id={`delete-${rowIndex}`}
className="anchor-action-delete"
href="#foo"
onClick={(e) => {
e.preventDefault();
handleDelete(row);
}}>
thanks have a great day
There are 2 problems in your code:
req.params.id is meant for urls of the form /delete/:id which is obviously not your route, you should change it to req.query.id instead which matches query parameters in the url such as /delete?id=123.
The default type of _id is ObjectId, under the assumption you did not change this you need to cast your req.query.id which is type string to ObjectId.
It looks like you're using mongoose so here's mongoose syntax:
const mongoose = require("mongoose");
router.delete("/delete", (req, res) => {
Customer.findOneAndDelete({ _id: new mongoose.Types.ObjectId(req.query.id) }, (err, Customer) => {
if (!err) {
res.json({ msg: "customer deleted", deleted: Customer });
} else {
console.log("Error removing :" + err);
}
});
});
For nodejs native Mongo package:
import {ObjectId} from "mongodb";
...
new ObjectId(req.query.id)
I dont see you sent the id to the backend but you are trying to retrieve it from req.params.id try passing the id like "delete/:id" at the end of the link and specify this in the routes aswell.
if that doesnt fix try the below code this for routes
if nothing works check this, In the component you need to send the id(object id) but i see "row" what is the value of row? if the row value is not the id in the database then it wont delete. if this your issue try inspecting the code by keeping breakpoints or write a console.log() to check the value of "row" .
try {
const removedProject = await Customer.remove({
_id: req.params.id
})
res.json(removedProject)
} catch (err) {
res.json({
message: err
})
}
I got this helper function:
const Account = require('../models/account');
exports.sendInvites = (accountIds, invite, callback) => {
if (!accountIds) {
callback('No account ids provided', null, null);
return;
}
accountIds.forEach((id) => {
Account.findOneAndUpdate({_id: id}, {$push: {organisationInvites: invite}}, callback);
});
};
Then I have this route:
router.post('/organisations', auth.verifyToken, (req, res, next) => {
const organisation = new Organisation({
name: req.body.name,
email: req.body.email,
admins: [req.body.createdBy],
createdBy: req.body.createdBy
});
organisation.save((err, organisation) => {
if (err) {
return res.status(500).json({
error: err,
data: null
});
}
organisationUtils.sendInvites(req.body.invites, {
inviter: req.body.createdBy,
organisation: organisation._id
}, (err, account, response) => {
if (err) {
return res.status(500).json({
error: err,
data: null
});
}
res.json({
error: null,
data: organisation
});
});
});
});
I get a Error: Can't set headers after they are sent. error for the
res.json({
error: null,
data: organisation
});
part but I can't understand why this is happening. I tried looking at the accepted answer here Error: Can't set headers after they are sent to the client, did some digging but couldn't find any specific reason still what's happening in my particular example above. Any ideas?
You are calling the callback multiple times, and so res.json multiple times. Gather the data from all database request then perform an unique res.json.
accountIds.forEach((id) => {
Account.findOneAndUpdate(
{_id: id},
{$push: {organisationInvites: invite}},
callback,
);
});
Something like :
var allData = [];
var nbRequestDone = 0;
var waitAllCallback = function (data, err) {
if (err) {
callback(err);
nbRequestDone = accountIds.length;
return;
}
nbRequestDone += 1;
allData.push(data);
if (nbRequestDone === accountIds.length) {
callback(false, allData);
}
};
accountIds.forEach((id) => {
Account.findOneAndUpdate(..., waitAllCallback);
});
this video covers the Error regarding "Error: Can't set headers after they are sent".
https://www.youtube.com/watch?v=rKTlakY8j2M
In summary of the video, this error shows up when you have an extra callback in your code. Hope this helps. Been struggling with this one too for quite some time.
Making an API with Node/Express + Mongo.
I'm writing some unit test and I observed if I try to get /profile/1 for _id=1 (I let mongo put the ID by default so I cannot have _id=1) i got this error
MongooseError: Cast to ObjectId failed for value "1" at path "_id"
I thought I will have an empty object User.
function getProfile(req, res) {
const userId = req.params.userId
User.findById(userId, "-password", (err, user) => {
if (err) {
console.log(err);
res.status(400)
res.json({
success: false,
err
})
res.end()
return
}
if (!user) {
res.status(404)
res.json({
success: false,
message: `Cannot find an User with the userId: ${userId}`
})
res.end()
return
}
res.json({
success: true,
user: user
})
res.end()
return
})
}
My test :
describe('Test /profile route', () => {
it('shouldn\'t find Joe Doe\'s profile with a wrong ID\n', (done) => {
chai.request(server)
.get(`/profile/1`)
.end((err, res) => {
expect(res).to.have.status(404)
done()
})
})
I thought I would have an error 404 (second if, and I know it's not the right code error, just a quick way for me to see where my test goes) but I got a 400 -> meaning an error is return.
I read mongoose documentation and I don't really see ho they explain the return value with the different methods.
The problem is that '1' is not a valid mongoose object id. Therefore it is trying to compare different types.
Try casting it to a object id like so:
userId = mongoose.Types.ObjectId(userId)
and then run your query
User.findById(userId, "-password", (err, user) => { .... });