I have a route in my app that calls the mongoose method findByIdAndRemove. When I test this route in postman, I can successfully delete documents in my database, but when I call this method from my javascript file in the client, I get an error.
I getting a 404 (the response status I dictated if no document can be found). I also get an error in the terminal saying "can't set headers after they are sent." I'm not sure why I'm getting this error. Why is my route working in postman, but not when I call it from the client-side?
How should I get this working?
Here is my route on the server-side:
exports.deleteEmployee = function (req, res, next) {
const id = mongoose.Types.ObjectId(req.body.id);
Employee.findByIdAndRemove(id, (err, employee) => {
if (err) { return next(err); }
// if no employee with the given ID is found throw 400
if (!employee) { res.status(404).json('No employee with that ID'); }
res.status(200).json(employee);
});
};
Here is where I call this route from the client-side:
export const employeeDelete = ({ id }) => {
const props = { id };
return () => {
axios.delete(`${api.API_ROUTE}/employee/delete`, props)
.then(() => {
// push user back to EmployeeList and reset view stack
Actions.employeeList({ type: 'reset' });
})
.catch(err => {
console.log(err);
});
};
};
You're getting "can't set headers after they are sent." error because you're trying to respond with 200 code after having responded with 400 code.
You should surround the response statements with a if/else statement:
if (!employee) { res.status(404).json('No employee with that ID'); }
else{res.status(200).json(employee);}
It turns out the axios delete method does not take a data object, so when I passed the object called props, it never reached the server. I instead passed id as a url parameter like this:
export const employeeDelete = ({ id }) => {
return () => {
axios.delete(`${api.API_ROUTE}/employee/delete/${id}`)
.then(() => {
// push user back to EmployeeList and reset view stack
Actions.employeeList({ type: 'reset' });
})
.catch(err => {
console.log(err);
});
};
};
Related
I make a crud with products
I send an http request to the /api/deleteProduct route with the product id to retrieve it on the server side and delete the product by its id
To create a product it works only the delete does not work
pages/newProduct.js :
useEffect(() => {
async function fetchData() {
const res = await axios.get('/api/products');
setProducts(res.data);
}
fetchData();
}, []);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('picture', picture);
formData.append('name', name);
formData.append('price', price);
formData.append('category', category);
formData.append('description', description);
try {
const res = await axios.post('/api/createProduct', formData);
console.log(res.data);
} catch (error) {
console.log(error);
}
};
const handleDelete = async (id) => {
try {
await axios.delete(`/api/deleteProduct?id=${id}`);
setProducts(products.filter(product => product._id !== id));
} catch (error) {
console.log(error);
}
};
api/deleteProduct.js :
import Product from '../../models/Products';
import { initMongoose } from '../../lib/mongoose';
initMongoose();
export const handleDelete = async (req, res) => {
if (req.method === 'DELETE'){
try {
const { id } = req.params
const product = await Product.findByIdAndRemove(id);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}
return res.status(200).json({ message: 'Product deleted successfully' });
} catch (error) {
console.log(error);
return res.status(500).json({ message: 'Database error' });
}
}};
I have a 500 error but no error in the server side console and the console.log is not showing like the file was not read
Based on the code you've shared, it seems that the problem may be with the way that the delete request is being handled on the frontend. Specifically, in this line:
await axios.delete("/api/deleteProduct", { params: { id } });
The delete request is supposed to receive the id of the product that should be deleted as a query parameter, but it is being passed as a request body.
Instead of passing it as a parameter, you should pass it as a query parameter by changing it to
await axios.delete(`/api/deleteProduct?id=${id}`);
Also, in your api/deleteProduct.js, you should change the following line:
const { id } = req.query;
to
const { id } = req.params;
Also, you should make sure that the server is running and that the api endpoint '/api/deleteProduct' is accessible and handling the request correctly.
For the last, make sure that the product model is imported and initialized correctly and the database connection is established.
Hope that it solves your problem or, at least, helps :))
I succeeded, I put this (server side):
const { id } = req. query;
and (client side):
await axios.delete(/api/deleteProduct?id=${id});
and I exported my function like this:
export default async function handleDelete(req, res) {
So on my listPage, I have 2 documents, where I want to be able to click the edit button, and it takes me to the editPage. It does do that right now. but what I have it doing, is making the request through an axios.post, so that it sends the id of the document to the backend, and then sends the results to the front end, where it'll only display the one document according to it's id. here's what I have:
listPage:
const editById = (id) => {
console.log(id);
axios
.post(`/getDocToEdit`, { id: id })
.then(() => {
console.log(id, " worked");
window.location = "/admin/services/:site";
})
.catch((error) => {
// Handle the errors here
console.log(error);
});
};
then it hits this backend route:
app.post('/getDocToEdit', (req, res) => {
var id = req.body.id;
ServicesModel.findOne({_id: id}, function(err,result) {
console.log(result);
res.status(200).send(result)
});
})
then I am just trying to display the document on screen in my editPage, but it doesn't load the result that I am sending through res.status(200).send(result). I have just a table that is supposed to show the record. am I supposed to be doing a call from the front end again or something?
you should save post result in your frontend:
const editById = (id) => {
console.log(id);
axios
.post(`/getDocToEdit`, { id: id })
.then((RESPONSE) => {
console.log(RESPONSE); // do it and if you have the response, everything
is fine and you can use it as the returned data
console.log(id, " worked");
window.location = "/admin/services/:site";
})
.catch((error) => {
// Handle the errors here
console.log(error);
});
I'm new to Next Js and functional comoponents. I'm trying to retrieve data from /api/retrieve2
//this is retrieve page
export default function Retrieve() {
const onSubmit = async data => {
const { user } = await axios.post("/api/retrieve2", data);
console.log(user) // user here is undefined
};
return (...);
}
//this is retrieve2, inside the API folder
export default async (req, res) => {
try {
const { data } = await axios.post(myBackendUrl, req.body);
console.log(data) //this is printing the right data - { email: 'casas#gmail.com', code: '123123' }
res.json(data);
} catch (e) {
res.json({ err: e.message || e });
}
};
What am I missing, is this something about Next? About functional components?
You should read about ES6 destructuring
You try to destructure user but the axios respons witch is a object doesnt contain the key user
For data it works because there is a data property in the response
Here are all properties that you can destructure:
{ data, status, statusText, headers, config, request }
You need to get the full URL to make http request to using getInitialProps, here Home is the name of your component
const Home = ({ENDPOINT}) => {
const onSubmit = async data => {
const { data } = await axios.post(`${ENDPOINT}/api/retrieve2`, data);
// consider changing `user` here to `data` since Axios stores response in data object
console.log(data) // should be defined
};
return (...);
}
Home.getInitialProps = ctx => {
const ENDPOINT = getEndpoint(ctx.req);
return { ENDPOINT };
};
// You should store this somewhere you can reuse it
export function getEndpoint(req) {
return !!req
? `${req.headers['x-forwarded-proto']}://${req.headers['x-forwarded-host']}`
: window.location.origin;
}
I'm using axios to connect mysql db with vue frontend, and it's almost done. But the problem is that this.$http.delete() somehow doesn't work at all. I've looked it up but those solutions didn't work. (wrap it {data: book_no}, or {params: book_no}). But it seems like I need to wrap it anyway as an object from vue component when I request(for delete only) the data(req.body.book_no gets undefined data. that's why I added), so I tried few different formats, but it only returns 500 internal server error. Which makes even more 'what?????????' because almost same format of other functions(CRU) are working perfectly.
Please help me out this this.$http.delete method!
Frontend vue component:
btnDelete(book) {
// console.log(book_no);
let book_no = book.book_no;
if (confirm(book_no + " 를 삭제하시겠습니까?")) {
this.$http
.delete("/api/books/delbook", {
book: {
book_no
}
})
.then(res => {
console.log(res.data);
})
.catch(err => console.log(err));
} else {
return;
}
Backend Books.js delete part
router.delete('/delbook', function (req, res) {
console.log(123)
let bookNo = req.body.book.book_no
console.log(bookNo)
let bookObj = {
'book_no': bookNo
}
console.log(bookObj)
let sql = `DELETE FROM books WHERE book_no = ${bookNo}`
console.log(6666)
db.query(sql, bookObj, function (err, result) {
if (err) throw err;
console.log(err)
console.log(result)
console.log(3234234)
res.send(result)
})
})
error(the only error I've got):
DELETE http://localhost:8080/api/books/delbook 500 (Internal Server Error)
I want to show message after deleting user but I don't know how to do it. I tried to create req.session properties and then use them but they are not available in GET route. Do you know how to fix this code?
router.get("/", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
let currentMessage = req.session.message;
let currentState = req.session.state;
req.session.message = undefined;
req.session.state = undefined;
console.log(currentState, currentMessage); //undefined
user.getAll()
.then(result => {
res.render("users", {
name: req.user,
users: result,
msg: currentMessage,
state: currentState
})
})
});
// delete route
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
req.session.message = "Some message!"
req.session.state = true;
})
});
// jquery
function ajaxDelete(ev, url) {
ev.preventDefault();
$.ajax({
url: url,
type: "DELETE"
});
}
delBtn.click(function(e) {
var user = $(this).data("user");
ajaxDelete(e, "/users/delete/" + user);
window.location.href = "/users";
})
Use res parameter, and make a variable called message
const message= 'MyMessage';
then
res.json ({message}) // es6 feature
output
{"message":"myMessage"}
In your scenario, as far as I understand you want to send the JSON in response. You can use this code
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
var response = { message : "Some message!",
state : true };
return res.json(response);
})
});
the keyword 'return' is as per your requirement
router and session are middleware to any nodeJs App,If the router is added before session like this:
app.use(router)
app.use(session(...));
Then the session middleware won't get called for any requests that get handled by router.
Hence change the order of adding router and session middleware,like this
app.use(session(...));
app.use(router)