I am trying to do error handling for POST with the same user email with the following(using superagent):
export function signUpUser(userData) {
return async dispatch => {
try {
const currentUser = await request.post(`${url}/signup`).send(userData);
set(window.localStorage, 'x-auth', currentUser);
dispatch(signUpSuccessObject(userData));
} catch (error) {
dispatch(signUpFailObject(error));
}
};
}
I want to get the following which I can see in my network tab:
{"name":"SequelizeUniqueConstraintError","errors":[{"message":"email
must be unique","type":"unique
violation","path":"email","value":"leo#fsl.co","origin":"DB","instance":
But instead all I get is:
Bad Request
My controller for API:
User.create(
Object.assign(req.body, {
password: bcrypt.hashSync(req.body.password, 10),
})
)
.then(() => {
const myToken = jwt.sign({email: req.body.email}, 'leogoesger');
res.status(200).send(myToken);
})
.catch(err => res.status(400).send(err));
},
https://github.com/visionmedia/superagent/issues/1074
^^ Used this as a reference.
Basically, I need error.response. This will give me the entire object, which will allow me to get access to the error message.
So full working code would be:
export function signUpUser(userData) {
return async dispatch => {
try {
const currentUser = await request
.post(`${url}/signup`)
.send(userData)
.type('json');
set(window.localStorage, 'x-auth', currentUser);
dispatch(signUpSuccessObject(userData));
} catch (e) {
dispatch(signUpFailObject(e.response.body));
}
};
}
res.send() will send plain text/html responses.
Use res.json(myToken) and res.status(400).json(err) for a JSON API.
Related
Error:
Actions must be plain objects. Instead, the actual type was: 'string'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions.
The below code is the client side where I dispatch the selected user id to actions.
const friendHandle = (e) => {
e.preventDefault()
setSwitch(false)
setFriend(!friend)
dispatch(friendUser(id))//id is the id from params of selected users
setFetchAgain(!fetchAgain)
}
useEffect(() => {
if(currentUser){
currentUser?.friends?.map(friends => {
console.log(friends._id)
console.log(currentProfile._id)
if(friends._id===currentProfile._id){
return setFriend(true)
}
})
}else{
return setFriend(false)
}
},[currentUser,currentProfile])
below is actions.js for the above code
export const friendUser = (id) => async (dispatch) => {
try {
await api.friendUser(id)
dispatch(id)
} catch (error) {
console.log(error)
}
}
I am trying to pass the id of the selected user but I am getting an error. I am new to React so I am not able to understand.
remove the dispatch(id) from the action, might be some copy\paste or merge error
I have following code calling post and get API calls.
Problem is I am getting customerDatas undefined..
Any idea why this issue is.
try {
let dataPromises = await axios.post('customers', {}, { baseURL: baseURL });
var customerDatas = await Promise.all(dataPromises.data.customerIds.map( async (customerId) =>{
await axios.get('customers/' + customerId, {baseURL : baseURL});
console.log(customerDatas);
}));
} catch (error) {
console.error(error);
}
As #Konrad Linkowski mention in the comments, you do not return anything from map:
var customerDatas = await Promise.all(dataPromises.data.customerIds.map( async (customerId) => {
return axios.get('customers/' + customerId, {baseURL : baseURL});
}));
also, you cannot access customerDatas inside the map because it is not yet initalized.
I'm new to fetching and posting data using an API, and I can't work out how to do something once my Post has been completed.
I have a function that calls the API with the Post data. I need to set the loading state to false once the Post has been completed. Everything works apart from that, the data gets sent to Mongo, I just need to turn off my loading spinner once it has completed.
How do I do this, please?
This is how I'm trying to do it:
const postData = async () => {
setLoading(true)
await axios.post('/api/addData',form)
.then(response => {
setLoading(false)
})
}
And this is the API bit:
import { connectToDatabase } from "util/mongodb"
export default async (req, res) => {
const { db } = await connectToDatabase()
await db
.collection("posts")
.insertOne(req.body);
}
There is two potential problem in your code, first you're not sending any data back to the front in your backend code. Usually you send back the id of the inserted element (It can be usefull to do some mutation in your front), you'll also need to try catch your call to the db to notify that something went wrong to the front end side :
import { connectToDatabase } from "util/mongodb"
export default async (req, res) => {
try {
const { db } = await connectToDatabase()
const insertedPost = await db
.collection("posts")
.insertOne(req.body);
res.status(201).send(insertedPost.insertedId);
// again it's up to you to know what can be usefull to your front-end to use
// Look at http status code online to know what's the best fit
} catch (err) {
res.status(500).send(err.message);
// send whatever that can be usefull for your front end to handle the error
}
}
In your front-end code you're using await with .then, it's weird usage. You can put your setLoading(false) after the await without the .then but you'll still need to try catch it. What I prefer to do is using the finally block to stop loading, so if my api call fail the loading is still stopped :
const postData = async () => {
setLoading(true)
try {
const response = await axios.post('/api/addData',form)
// do something with response
} catch (err) {
// notify user that something went wrong
} finally {
setLoading(false);
}
}
const postData = () => {
setLoading(true)
axios.post('/api/addData',form)
.then(response => {
// do something with response
})
.catch((err) => {
// notify user that something went wrong
})
.finally(() => {
setLoading(false);
})
}
I am developing a NodeJS application and I am using mongoose for saving data into my MongoDB database.
My controller can take a POST request at the /register url with some data. That looks like this:
router.post("/register", async (req: Request, res: Response) => {
const accountModel: IRegistrationAccount = {
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
repeatedPassword: req.body.repeatedPassword,
};
try {
registerAccount(accountModel);
res.status(OK).send("Registration successful.");
} catch (err) {
res.status(NOT_ACCEPTABLE).send(err);
}
});
As you can see, I want to return an error message to the user so that they know exactly what went wrong. This is the registerAccount method:
export function registerAccount(accountModel: IRegistrationAccount) {
if (accountModel.firstName.length === 0)
throw "Your first name may not be empty.";
if (accountModel.email.length < 3) throw "Your email is too short.";
if (accountModel.password !== accountModel.repeatedPassword)
throw "The passwords You entered don't match.";
if (accountModel.password.length < 8) throw "Your password is too short.";
const account = new Account(accountModel);
account.save(function (err) {
if (err) return logger.err(err);
return logger.info("Created account.");
});
}
When there is something wrong the the data that the user entered, I return an error message using throw, which is then later caught in the controller. The problem is: how do I know if the callback function inside save threw an error and how do I handle that error? This is my first time working with Node, I tried searching around but can't find a suitable answer.
save method can return Promise so you don't need to use a callback at all:
export async function registerAccount(accountModel: IRegistrationAccount) {
if (accountModel.firstName.length === 0)
throw "Your first name may not be empty.";
if (accountModel.email.length < 3) throw "Your email is too short.";
if (accountModel.password !== accountModel.repeatedPassword)
throw "The passwords You entered don't match.";
if (accountModel.password.length < 8) throw "Your password is too short.";
const account = new Account(accountModel);
await account.save();
}
and add await at the line where you call this function:
try {
await registerAccount(accountModel);
logger.info("Created account.")
res.status(OK).send("Registration successful.");
} catch (err) {
logger.err(err)
res.status(NOT_ACCEPTABLE).send(err);
}
I'd promisify account with util.promisify, and then return the Promise and .catch it in the caller:
return accountSavePromisified().then(() => {
logger.info("Created account.");
});
try {
registerAccount(accountModel)
.then(() => {
res.status(OK).send("Registration successful.");
})
.catch((err) => {
// Catch asynchronous errors (thrown by `.save`):
res.status(NOT_ACCEPTABLE).send(err);
})
} catch (err) {
// Catch synchronous errors (thrown by your validator):
res.status(NOT_ACCEPTABLE).send(err);
}
If you don't care about differentiating errors thrown by .save from errors thrown by your validator, you could also await the call of registerAccount instead of calling .then on it.
You could also consider making the control flow a bit easier to understand by returning error strings from registerAccount instead of throwing, eg return 'Your first name may not be empty.':
const result = registerAccount(accountModel);
if (typeof result === 'string') {
res.status(NOT_ACCEPTABLE).send(result);
return;
}
result.then(() => {
res.status(OK).send("Registration successful.");
})
.catch((err) => {
res.status(NOT_ACCEPTABLE).send(result);
});
Hey guys so I am trying to add state data from my store into a string in one of my axios calls within actions. Here is my store:
export const store = new Vuex.Store
({
state: {
participants: [],
filterTags: ["foo", "swag"],
page: 1,
perPage: 2,
filterTagName: "",
}
}
Here is my action call:
actions: {
async loadParticipants ({commit}) {
try {
console.log(this.state.page);
await axios
.get('/dash/participant?perPage=2&page=1&string=f')
.then(r => r.data)
.then(participants => {
console.log(participants.docs);
console.log("Hit me");
commit('setParticipants', participants)
})
}
catch (e) {
if (e.response)
console.log(e.response);
throw e
}
}
I want to add the store's state data where it says { INSERT DATA HERE } within the axios call:
.get('/dash/participant?perPage={INSERT DATA HERE }&page={ INSERT DATA HERE }&string=f')
Any input appreciated thank you!
In your action, you have access to the whole store, so instead to just getting only the commit declaring the param as ({commit}), you can add the state too:
async loadParticipants ({commit, state}) {
So you can use the state variable in your method body:
actions: {
async loadParticipants ({commit, state}) {
try {
console.log(this.state.page);
await axios
.get(`/dash/participant?perPage=${state.perPage}&page=${state.page}&string=${state.filterTagName}`)
.then(r => r.data)
.then(participants => {
console.log(participants.docs);
console.log("Hit me");
commit('setParticipants', participants)
})
}
catch (e) {
if (e.response)
console.log(e.response);
throw e
}
}
}
So you just want to fill your query params with the values from your vuex store?
Just pass the state into your action. And then you can add the state to your query params with a little help of template iterals. ${some-js-variable}
You can also directly destruct the response and grab the data.
Not sure why you make promise like then() statements if you use async and await.
actions: {
async loadParticipants ({commit, state}) {
try {
const {data} = await axios.get(`/dash/participant?perPage=${state.perPage}&page=${state.page}&string=f`)
console.log(data)
}
catch (e) {
if (e.response)
console.log(e.response);
throw e
}
}