Test method is overspecified - javascript

I have this before function in my test:
before((done) => {
const cognito = new Cognito();
return cognito.authUser(
'john#doe.com',
'password',
)
.then((res) => {
AuthToken += res.AuthenticationResult.IdToken;
done();
})
.catch((err) => {
done(err);
});
});
It throws this error:
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
I thought this may have been the fix:
before((done) => {
const cognito = new Cognito();
return new Promise(function(resolve) {
cognito.authUser(
'john#doe.com',
'password',
)
})
.then((res) => {
AuthToken += res.AuthenticationResult.IdToken;
done();
})
.catch((err) => {
done(err);
});
});
but it gives me this error:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
How do I resolve this?

The error explains a little bit.
You can't use both callback and a return.
You have 2 options:
callback (the done parameter)
before((done) => {
const cognito = new Cognito();
cognito.authUser(
'john#doe.com',
'password',
)
.then((res) => {
AuthToken += res.AuthenticationResult.IdToken;
done();
})
.catch((err) => done(err));
});
or
Return promise
before(() => {
const cognito = new Cognito();
return cognito.authUser(
'john#doe.com',
'password',
)
.then((res) => {
AuthToken += res.AuthenticationResult.IdToken;
})
});

Related

fetch to call badrequest message from dotnet [duplicate]

Here's what I have going:
import 'whatwg-fetch';
function fetchVehicle(id) {
return dispatch => {
return dispatch({
type: 'FETCH_VEHICLE',
payload: fetch(`http://swapi.co/api/vehicles/${id}/`)
.then(status)
.then(res => res.json())
.catch(error => {
throw(error);
})
});
};
}
function status(res) {
if (!res.ok) {
return Promise.reject()
}
return res;
}
EDIT: The promise doesn't get rejected, that's what I'm trying to figure out.
I'm using this fetch polyfill in Redux with redux-promise-middleware.
Fetch promises only reject with a TypeError when a network error occurs. Since 4xx and 5xx responses aren't network errors, there's nothing to catch. You'll need to throw an error yourself to use Promise#catch.
A fetch Response conveniently supplies an ok , which tells you whether the request succeeded. Something like this should do the trick:
fetch(url).then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
The following login with username and password example shows how to:
Check response.ok
reject if not OK, instead of throw an error
Further process any error hints from server, e.g. validation issues
login() {
const url = "https://example.com/api/users/login";
const headers = {
Accept: "application/json",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify({
email: this.username,
password: this.password,
}),
})
.then((response) => {
// 1. check response.ok
if (response.ok) {
return response.json();
}
return Promise.reject(response); // 2. reject instead of throw
})
.then((json) => {
// all good, token is ready
this.store.commit("token", json.access_token);
})
.catch((response) => {
console.log(response.status, response.statusText);
// 3. get error messages, if any
response.json().then((json: any) => {
console.log(json);
})
});
},
Thanks for the help everyone, rejecting the promise in .catch() solved my issue:
export function fetchVehicle(id) {
return dispatch => {
return dispatch({
type: 'FETCH_VEHICLE',
payload: fetch(`http://swapi.co/api/vehicles/${id}/`)
.then(status)
.then(res => res.json())
.catch(error => {
return Promise.reject()
})
});
};
}
function status(res) {
if (!res.ok) {
throw new Error(res.statusText);
}
return res;
}
For me,
fny answers really got it all. since fetch is not throwing error, we need to throw/handle the error ourselves.
Posting my solution with async/await. I think it's more strait forward and readable
Solution 1: Not throwing an error, handle the error ourselves
async _fetch(request) {
const fetchResult = await fetch(request); //Making the req
const result = await fetchResult.json(); // parsing the response
if (fetchResult.ok) {
return result; // return success object
}
const responseError = {
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
};
const error = new Error();
error.info = responseError;
return (error);
}
Here if we getting an error, we are building an error object, plain JS object and returning it, the con is that we need to handle it outside.
How to use:
const userSaved = await apiCall(data); // calling fetch
if (userSaved instanceof Error) {
debug.log('Failed saving user', userSaved); // handle error
return;
}
debug.log('Success saving user', userSaved); // handle success
Solution 2: Throwing an error, using try/catch
async _fetch(request) {
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok) {
return result;
}
const responseError = {
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
};
let error = new Error();
error = { ...error, ...responseError };
throw (error);
}
Here we are throwing and error that we created, since Error ctor approve only string, Im creating the plain Error js object, and the use will be:
try {
const userSaved = await apiCall(data); // calling fetch
debug.log('Success saving user', userSaved); // handle success
} catch (e) {
debug.log('Failed saving user', userSaved); // handle error
}
Solution 3: Using customer error
async _fetch(request) {
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok) {
return result;
}
throw new ClassError(result.message, result.data, result.code);
}
And:
class ClassError extends Error {
constructor(message = 'Something went wrong', data = '', code = '') {
super();
this.message = message;
this.data = data;
this.code = code;
}
}
Hope it helped.
2021 TypeScript Answer
What I do is write a fetch wrapper that takes a generic and if the response is ok it will auto .json() and type assert the result, otherwise the wrapper throws the response
export const fetcher = async <T>(input: RequestInfo, init?: RequestInit) => {
const response = await fetch(input, init);
if (!response.ok) {
throw response;
}
return response.json() as Promise<T>;
};
and then I'll catch errors and check if they are an instanceof Response. That way TypeScript knows that error has Response properties such as status statusText body headers etc. and I can apply a custom message for each 4xx 5xx status code.
try {
return await fetcher<LoginResponse>("http://localhost:8080/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ email: "user#example.com", password: "passw0rd" }),
});
} catch (error) {
if (error instanceof Response) {
switch (error.status) {
case 401:
throw new Error("Invalid login credentials");
/* ... */
default:
throw new Error(`Unknown server error occured: ${error.statusText}`);
}
}
throw new Error(`Something went wrong: ${error.message || error}`);
}
and if something like a network error occurs it can be caught outside of the instanceof Response check with a more generic message i.e.
throw new Error(`Something went wrong: ${error.message || error}`);
The answer by #fny (the accepted answer) didn't work for me. The throw new Error() wasn't getting picked up by the .catch. My solution was to wrap the fetch with a function that builds a new promise:
function my_fetch(url, args) {
return new Promise((resolve, reject) => {
fetch(url, args)
.then((response) => {
response.text().then((body) => {
if (response.ok) {
resolve(body)
} else {
reject(body)
}
})
})
.catch((error) => { reject(error) })
})
}
Now every error and non-ok return will be picked up by the .catch method:
my_fetch(url, args)
.then((response) => {
// Do something with the response
})
.catch((error) => {
// Do something with the error
})
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
fetch("https://example.com/api/users")
.then(handleErrors)
.then(response => console.log("ok") )
.catch(error => console.log(error) );
I wasn't satisfied with any of the suggested solutions, so I played a bit with Fetch API to find a way to handle both success responses and error responses.
Plan was to get {status: XXX, message: 'a message'} format as a result in both cases.
Note: Success response can contain an empty body. In that case we fallback and use Response.status and Response.statusText to populate resulting response object.
fetch(url)
.then(handleResponse)
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
export const handleResponse = (res) => {
if (!res.ok) {
return res
.text()
.then(result => JSON.parse(result))
.then(result => Promise.reject({ status: result.status, message: result.message }));
}
return res
.json()
.then(result => Promise.resolve(result))
.catch(() => Promise.resolve({ status: res.status, message: res.statusText }));
};
I just checked the status of the response object:
$promise.then( function successCallback(response) {
console.log(response);
if (response.status === 200) { ... }
});
Hope this helps for me throw Error is not working
function handleErrors(response) {
if (!response.ok) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject({
status: response.status,
statusText: response.statusText,
});
}, 0);
});
}
return response.json();
}
function clickHandler(event) {
const textInput = input.value;
let output;
fetch(`${URL}${encodeURI(textInput)}`)
.then(handleErrors)
.then((json) => {
output = json.contents.translated;
console.log(output);
outputDiv.innerHTML = "<p>" + output + "</p>";
})
.catch((error) => alert(error.statusText));
}
Another (shorter) version that resonates with most answers:
fetch(url)
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(json => doStuff(json)) //all good
//next line is optional
.catch(response => handleError(response)) //handle error

Fetch API POST in React app not logging errors in catch block from express/node server [duplicate]

Here's what I have going:
import 'whatwg-fetch';
function fetchVehicle(id) {
return dispatch => {
return dispatch({
type: 'FETCH_VEHICLE',
payload: fetch(`http://swapi.co/api/vehicles/${id}/`)
.then(status)
.then(res => res.json())
.catch(error => {
throw(error);
})
});
};
}
function status(res) {
if (!res.ok) {
return Promise.reject()
}
return res;
}
EDIT: The promise doesn't get rejected, that's what I'm trying to figure out.
I'm using this fetch polyfill in Redux with redux-promise-middleware.
Fetch promises only reject with a TypeError when a network error occurs. Since 4xx and 5xx responses aren't network errors, there's nothing to catch. You'll need to throw an error yourself to use Promise#catch.
A fetch Response conveniently supplies an ok , which tells you whether the request succeeded. Something like this should do the trick:
fetch(url).then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
The following login with username and password example shows how to:
Check response.ok
reject if not OK, instead of throw an error
Further process any error hints from server, e.g. validation issues
login() {
const url = "https://example.com/api/users/login";
const headers = {
Accept: "application/json",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify({
email: this.username,
password: this.password,
}),
})
.then((response) => {
// 1. check response.ok
if (response.ok) {
return response.json();
}
return Promise.reject(response); // 2. reject instead of throw
})
.then((json) => {
// all good, token is ready
this.store.commit("token", json.access_token);
})
.catch((response) => {
console.log(response.status, response.statusText);
// 3. get error messages, if any
response.json().then((json: any) => {
console.log(json);
})
});
},
Thanks for the help everyone, rejecting the promise in .catch() solved my issue:
export function fetchVehicle(id) {
return dispatch => {
return dispatch({
type: 'FETCH_VEHICLE',
payload: fetch(`http://swapi.co/api/vehicles/${id}/`)
.then(status)
.then(res => res.json())
.catch(error => {
return Promise.reject()
})
});
};
}
function status(res) {
if (!res.ok) {
throw new Error(res.statusText);
}
return res;
}
For me,
fny answers really got it all. since fetch is not throwing error, we need to throw/handle the error ourselves.
Posting my solution with async/await. I think it's more strait forward and readable
Solution 1: Not throwing an error, handle the error ourselves
async _fetch(request) {
const fetchResult = await fetch(request); //Making the req
const result = await fetchResult.json(); // parsing the response
if (fetchResult.ok) {
return result; // return success object
}
const responseError = {
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
};
const error = new Error();
error.info = responseError;
return (error);
}
Here if we getting an error, we are building an error object, plain JS object and returning it, the con is that we need to handle it outside.
How to use:
const userSaved = await apiCall(data); // calling fetch
if (userSaved instanceof Error) {
debug.log('Failed saving user', userSaved); // handle error
return;
}
debug.log('Success saving user', userSaved); // handle success
Solution 2: Throwing an error, using try/catch
async _fetch(request) {
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok) {
return result;
}
const responseError = {
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
};
let error = new Error();
error = { ...error, ...responseError };
throw (error);
}
Here we are throwing and error that we created, since Error ctor approve only string, Im creating the plain Error js object, and the use will be:
try {
const userSaved = await apiCall(data); // calling fetch
debug.log('Success saving user', userSaved); // handle success
} catch (e) {
debug.log('Failed saving user', userSaved); // handle error
}
Solution 3: Using customer error
async _fetch(request) {
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok) {
return result;
}
throw new ClassError(result.message, result.data, result.code);
}
And:
class ClassError extends Error {
constructor(message = 'Something went wrong', data = '', code = '') {
super();
this.message = message;
this.data = data;
this.code = code;
}
}
Hope it helped.
2021 TypeScript Answer
What I do is write a fetch wrapper that takes a generic and if the response is ok it will auto .json() and type assert the result, otherwise the wrapper throws the response
export const fetcher = async <T>(input: RequestInfo, init?: RequestInit) => {
const response = await fetch(input, init);
if (!response.ok) {
throw response;
}
return response.json() as Promise<T>;
};
and then I'll catch errors and check if they are an instanceof Response. That way TypeScript knows that error has Response properties such as status statusText body headers etc. and I can apply a custom message for each 4xx 5xx status code.
try {
return await fetcher<LoginResponse>("http://localhost:8080/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ email: "user#example.com", password: "passw0rd" }),
});
} catch (error) {
if (error instanceof Response) {
switch (error.status) {
case 401:
throw new Error("Invalid login credentials");
/* ... */
default:
throw new Error(`Unknown server error occured: ${error.statusText}`);
}
}
throw new Error(`Something went wrong: ${error.message || error}`);
}
and if something like a network error occurs it can be caught outside of the instanceof Response check with a more generic message i.e.
throw new Error(`Something went wrong: ${error.message || error}`);
The answer by #fny (the accepted answer) didn't work for me. The throw new Error() wasn't getting picked up by the .catch. My solution was to wrap the fetch with a function that builds a new promise:
function my_fetch(url, args) {
return new Promise((resolve, reject) => {
fetch(url, args)
.then((response) => {
response.text().then((body) => {
if (response.ok) {
resolve(body)
} else {
reject(body)
}
})
})
.catch((error) => { reject(error) })
})
}
Now every error and non-ok return will be picked up by the .catch method:
my_fetch(url, args)
.then((response) => {
// Do something with the response
})
.catch((error) => {
// Do something with the error
})
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
fetch("https://example.com/api/users")
.then(handleErrors)
.then(response => console.log("ok") )
.catch(error => console.log(error) );
I wasn't satisfied with any of the suggested solutions, so I played a bit with Fetch API to find a way to handle both success responses and error responses.
Plan was to get {status: XXX, message: 'a message'} format as a result in both cases.
Note: Success response can contain an empty body. In that case we fallback and use Response.status and Response.statusText to populate resulting response object.
fetch(url)
.then(handleResponse)
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
export const handleResponse = (res) => {
if (!res.ok) {
return res
.text()
.then(result => JSON.parse(result))
.then(result => Promise.reject({ status: result.status, message: result.message }));
}
return res
.json()
.then(result => Promise.resolve(result))
.catch(() => Promise.resolve({ status: res.status, message: res.statusText }));
};
I just checked the status of the response object:
$promise.then( function successCallback(response) {
console.log(response);
if (response.status === 200) { ... }
});
Hope this helps for me throw Error is not working
function handleErrors(response) {
if (!response.ok) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject({
status: response.status,
statusText: response.statusText,
});
}, 0);
});
}
return response.json();
}
function clickHandler(event) {
const textInput = input.value;
let output;
fetch(`${URL}${encodeURI(textInput)}`)
.then(handleErrors)
.then((json) => {
output = json.contents.translated;
console.log(output);
outputDiv.innerHTML = "<p>" + output + "</p>";
})
.catch((error) => alert(error.statusText));
}
Another (shorter) version that resonates with most answers:
fetch(url)
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(json => doStuff(json)) //all good
//next line is optional
.catch(response => handleError(response)) //handle error

How to handle errors from within a callback in Nodejs

I have this code that invokes a function and has a callback with error and data parameters:
app.get('/lights', (req,res) => {
hue.getLights(function(err, data){
if(err) res.status(401).send("An error occured: ", err.message);
res.send(data);
});
})
The function that it invokes is:
let getLights = function(callback){
fetch(`http://${gateway}/api/${username}/lights`, {
method: 'GET'
}).then((res) => {
if(res.ok){
return res.json();
}else{
throw new Error(res.message);
}
}).then((json) => {
lightsArray = []
for (var i in json){
lightsArray.push(`ID: ${i} Name: ${json[i]['name']}`);
}
return callback(lightsArray);
});
}
When I make an error occur, the error isn't caught, nor is any error displayed, the app crashes with the message: UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().
Now I know I'm missing a lot, this is my first time using callbacks, let alone handling errors.
Could someone help me with making the error callback work, also show me some flaws in what I'm doing, as I know this won't catch every error that may happen, only errors caused by using the fetch function.
Thanks!
This is my other function (similar but uses a catch aswell, which I think I have done incorrectly too):
let getLightDetails = function (ID, callback) {
fetch(`http://${gateway}/api/${username}/lights/${ID}`, {
method: 'GET'
}).then((res) => {
if(res.ok){
return res.json();
}else{
throw new Error(res.message);
}
}).then((json) => {
return callback(json);
})
.catch((err) => {
console.log(err);
return callback(err.message);
});
}
Mixing callbacks and promises can make your code a bit messy. I would stick to promises:
app.get('/lights', (req, res) => {
return hue.getLights()
.then(data => {
res.send(data);
})
.catch(err => {
res.status(401).send("An error occured: ", err.message);
});
})
and hue.js
const fetch = require('node-fetch');
const gateway = "192.168.0.12";
const username = "username-A";
function fetchAPI(url, ...rest) {
return fetch(`http://${gateway}/api/${username}${url}`, ...rest);
}
function getLights() {
return fetchAPI(`/lights`)
.then(res => res.json())
.then(json => json.map((light, i) => `ID: ${i} Name: ${light.name}`));
}
function getLightDetails(id) {
return fetchAPI(`/lights/${id}`)
.then(res => res.json());
}
function getLightState(id) {
return fetchAPI(`/lights/${id}`)
.then(res => res.json())
.then(light => `Name: ${light.name} On: ${light.state.on}`);
}
function setLightState(id, state) {
return fetchAPI(`/lights/${id}/state`, {
method: 'PUT',
body: JSON.stringify({"on": state })
}).then(res => res.json());
}
module.exports = { getLights, getLightDetails, getLightState, setLightState };

Chaining synchronous Redux actions and consuming in component

I have two Redux actions which need to execute synchronously. requestStripeToken is called in my component (signupComponent.js), but in order to get a Stripe Token I first need to make a call to an internal API to get the current Stripe Key (as this changes depending on the environment and SKU). Both of these functions are set up as separate actions in my actions file (actions.js).
The issue I have it that I am not sure how to consume the requestStripeToken function in my component. I don't know whether it is an issue with what I am returning in the requestStripeToken action or whether the Promise consumption logic in my component needs to change. Note I am using redux-thunk middleware.
// actions.js
export function requestStripeToken(values) {
return function(dispatch) {
const { cardNumber, cvc, nameOnCard, expiryMonth, expiryYear, billingLine1, billingLine2, billingCity, billingState, billingZip, billingCountry } = values;
// We need to get the Stripe key before we can request a Stripe Token
return dispatch(getStripeSecretKey())
// Curried function necessary as getStripeSecretKey returns the fetch Promise inside of function(dispatch) ?
.then(() => (key) => {
console.log(key);
return new Promise((resolve, reject) => {
Stripe.setPublishableKey(key);
Stripe.card.createToken({
number: cardNumber,
cvc,
name: nameOnCard,
exp_month: expiryMonth,
exp_year: expiryYear,
address_line1: billingLine1,
address_line2: billingLine2,
address_city: billingCity,
address_state: billingState,
address_zip: billingZip,
address_country: billingCountry,
}, (status, response) => {
if (response.error) {
dispatch(addNotification({
message: response.error.message,
level: `error`,
autoDismiss: 0,
}));
reject();
}
return resolve(response.id);
});
});
});
};
}
export function getStripeSecretKey() {
return function(dispatch) {
return fetch(`${getAPIPath}api/stripeKey`, {
method: `GET`,
credentials: `include`,
headers: {
Accept: `application/json`,
},
})
.then(handleErrors)
.then((response) => {
response.json().then((res) => {
return res.data;
});
})
.catch(response => response.json().then((res) => {
dispatch(addNotification({
message: res.message,
level: `error`,
autoDismiss: 0,
}));
throw res;
}));
};
}
console.log(key) in this file never gets called.
// signupComponent.js
handleCreateAccountSubmit = (values) => {
this.setState({ submitting: true });
// We need the Stripe Token before we can signup the user so needs to be synchronous
this.props.actions.requestStripeToken(values)
.then((stripeToken) => {
console.log(stripeToken);
this.signupUser(values, stripeToken);
})
.catch(() => this.stopSubmission());
}
console.log(stripeToken) in this file returns:
ƒ (key) {
console.log(key);
return new Promise(function (resolve, reject) {
Stripe.setPublishableKey(key);
Stripe.card.createToken({
number: cardNumber,
…
You need to return Promises in your getStripeSecretKey() as well.
Dispatch returns what the action creator returns, so if you do:
export function getStripeSecretKey() {
return function(dispatch) {
return fetch(${getAPIPath}api/stripeKey, {
method:GET,
credentials:include,
headers: {
Accept:application/json,
},
})
.then(handleErrors) // also return Promise.reject() in errors
.then((response) => {
return response.json().then((res) => { // DONT BREAK RETURN CHAIN
return Promise.resolve(res.data); // RESOLVE
});
})
.catch(response => response.json().then((res) => {
dispatch(addNotification({
message: res.message,
level:error,
autoDismiss: 0,
}));
return Promise.reject(res); // REJECT
}));
};
}

Structure of multiple nested Mongoose promises

How would I structure a function that has multiple Mongoose.findOne() nested in each other?
I need to do something like
const userId = '...';
const postId = '...';
const imageId = '...';
User.findById(userId).then(user => {
if (!user) {
return res.status(400).json({
status: 'error',
err: 'User not found',
});
}
Post.findById(postId).then(post => {
if (!post) {
return res.status(400).json({
status: 'error',
err: 'Post not found',
});
}
Image.findById(imageId).then(image => {
if (!image) {
return res.status(400).json({
status: 'error',
err: 'Image not found',
});
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
}).catch(err => { .. });
}).catch(err => { .. });
}).catch(err => { .. });
Since Collection.findById() returns a promise, I guess I should use chaining instead of this structure.
So it might be something like
User
.findById(userId)
.then(user => Post.findById(postId))
.then(post => Image.findById(imageId))
.then(image => {
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
});
.catch(err => { .. });
but I don't know how to access the variables user, post, and image, and how to throw the errors, so I can access them in my catch statement.
Edit
I have tried this
async function getPostAsync() {
const userId = '597989c668189f31483ffdbf';
const postId = '597989c62624ea74750c74f8';
if (!userId) {
throw new Error('User id missing');
}
if (!postId) {
throw new Error('Post id missing');
}
const user = await User.findById(userId);
const post = await Post.findById(postId);
return post;
}
app.get('/', (req, res) => {
getPostAsync().then(post => {
res.json({
status: 'success',
});
}).catch(err => {
res.status(400).json({
status: 'error',
err
});
})
});
but I just receive
{
"status": "error",
"err": {}
}
Am I doing something wrong?
But I get the same result even with
async function getPostAsync() {
throw new Error('msg');
return Post.find();
}
so I might be calling the async function wrong.
You can use Promise.all:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(result)=>{
let user = result[0];
let post = result[1];
let image = result[2];
})
.catch(err => { .. });
Or with destructing assignment:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(([user, post, image])=>{...})
.catch(err => { .. });
You can't access those variables inside a later promise's then, but you can get round it by assigning the local resolved values to global variables
let globalUser, globalPost; // create variables for later
User
.findById(userId)
.then(user => {
globalUser = user; // assign to global
return Post.findById(postId)
})
.then(post => {
globalPost = post; // assign to global
return Image.findById(imageId)
})
.then(image => {
// DO SOMETHING WITH VARIABLES 'globalUser', 'globalPost', AND 'image'
})
.catch(err => {... });
EDIT: or when using async/await:
async function() {
const user = await User.findById(userId);
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
// do something with user, post and image
}
Seeing as your promises don't rely on each other you could also use Promise.all() in an async function:
async function() {
const result = await Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
]);
const [user, post, image] = result;
// do something with user, post and image
}
EDIT 2: Error handling
async function getImage() {
let user;
try {
user = await User.findById(userId);
} catch (error) { // deal with rejection of `User.findById`
// do something with error
}
// if these fail the entire function will throw
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
return image;
}
getImage()
.then(image => {... })
.catch(error => {... }); // deal with rejection of `getImage` as a whole
The above code showcases the ways you can handle errors in an async function. The first is how we deal with an error in the User.findById function, by simply wrapping it in a try catch block.
The second method is by simply letting the entire async function throw an error. I.e. if the Post.findById or Image.findById promises reject, the entire getImage() promise will reject, which you can deal with in the .catch() handler.

Categories

Resources