This is one of those problem that you can explain but do not know how to fix it. I have a simple store method:
exports.store = async (req, res) => {
const mydata = new MyModel(req.body)
await mydata.save(function(err,user) {
res.location('/mydata/id/' + user._id)
})
res.status(201).json({ data: userdata })
}
When it runs, I get the following error:
events.js:182
throw er; // Unhandled 'error' event
^
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:489:11)
at ServerResponse.setHeader (_http_outgoing.js:496:3)
at ServerResponse.header (.../node_modules/express/lib/response.js:730:10)
at ServerResponse.location (.../node_modules/express/lib/response.js:847:15)
at .../src/controllers/users-controller.js:26:13
at .../node_modules/mongoose/lib/model.js:3919:16
at .../node_modules/mongoose/lib/services/model/applyHooks.js:162:20
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
Process finished with exit code 1
I appears that the callback function runs separately and asynchronously because the res.status(201).json({ data: userdata }) seems to be producing the error and does not let me set the location header.
I've looked around for how to set the location header but none of the answers are like what I'm trying to do. This seems like something that should have been done before...? I'm looking for some help on how to do this...
You are mixing up two way of thinking :
Promises (with async/await in your case)
Callback
Use only one
try {
const user = await mydata.save();
res.location(`/mydata/id/${user._id}`);
// Other stuff ...
} catch(err) {
// Handle the errors
}
here you get an article about Promises into mongoose.
Related
I've made firebase cloud function which adds the claim to a user that he or she has paid (set paid to true for user):
const admin = require("firebase-admin");
exports.addPaidClaim = functions.https.onCall(async (data, context) => {
// add custom claim (paid)
return admin.auth().setCustomUserClaims(data.uid, {
paid: true,
}).then(() => {
return {
message: `Succes! ${data.email} has paid for the course`,
};
}).catch((err) => {
return err;
});
});
However, when I'm running this function: I'm receiving the following error: "Unhandled Rejection (RangeError): Maximum call stack size exceeded". I really don't understand why this is happening. Does somebody see what could cause what's getting recalled which in turn causes the function to never end?
Asynchronous operations need to return a promise as stated in the documentation. Therefore, Cloud Functions is trying to serialize the data contained by promise returned by transaction, then send it in JSON format to the client. I believe your setCustomClaims does not send any object to consider it as an answer to the promise to finish the process so it keeps in a waiting loop that throws the Range Error.
To avoid this error I can think of two different options:
Add a paid parameter to be able to send a JSON response (and remove the setCustomUserClaim if it there isn’t any need to change the user access control because they are not designed to store additional data) .
Insert a promise that resolves and sends any needed information to the client. Something like:
return new Promise(function(resolve, reject) {
request({
url: URL,
method: "POST",
json: true,
body: queryJSON //A json variable I've built previously
}, function (error, response, body) {
if (error) {
reject(error);
}
else {
resolve(body)
}
});
});
I've been trying to implement just a simple Firebase fetch since November. At this point, I wish I'd just created a new Rails api; it would have been faster.
But everyone insists Firebase is Oh So Simple.
In app.js,
import firebase from 'nativescript-plugin-firebase';
That part seems OK.
Instructions are all over the place after that.
The plugin's ReadMe suggests an initialization:
firebase.init({
// Optionally pass in properties for database, authentication and cloud messaging,
// see their respective docs.
}).then(
function () {
console.log("firebase.init done");
},
function (error) {
console.log("firebase.init error: " + error);
}
);
Several others have insisted that the init code is unnecessary. It does run without errors, but the code he gives after that produces nothing. Also,
const db = firebase.firestore;
const UserStatusCollection = db.collection("UserStatus");
UserStatusCollection.get();
produce an empty object {}.
Here's my Firebase collection:
If I wrap the firebase call in async/await (and no one is showing it as this complicated),
async function getFireStoreData() {
try {
let result = await this.UserStatusCollection.get();
console.log(result);
return result;
}
catch (error) {
console.error(
"UserStatusCollection.get()" + error
);
}
}
And call that
let temp2 = getFireStoreData();
console.log("temp2:" + temp2);
All I ever get is an object promise.
As I said, I wish I had just built up a new Rails API and had a far simpler life since November.
Your getFireStoreData method is asynchronous and you're not awaiting it. That is probably the reason why you're getting a promise back. Try to await getFireStoreData(). See if that works.
Since it's also a promise, you can try to use .then.
getFireStoreData().then(data => {
console.log(data);
})
I have a function that prepares the errors from backend to be easy for displaying in the components - it's named prepareErrorMessages. It accepts the response from the backend and some default error message.
So - in the saga I have this:
function* updateSomethingFlow(action) {
try {
const response = yield call(updateSomething, action.payload);
if (response) {
yield put({
type: UPDATE_SUCCESS
});
}
} catch (err) {
yield put({
type: UPDATE_FAILURE,
payload: prepareErrorMessages(err, 'Failed to update. Please, try again.')
});
}
}
So - am I wrong to modify the errors from the backend here?
Or is it better to do this in the reducer?
case UPDATE_FAILURE:
nextState = {
...state,
loading: false,
errors: prepareErrorMessages(payload, 'Failed to update. Please, try again.'),
};
break;
And also - why is it better to update there?
Personally, I think its right to do it in the reducer.
That is where you handle the responses. Action creators should only set the payload which could be some static data or a promise.
Dont see why you cannot transform/modify the received data there.
Personally, I would prefer to have it in the saga because I think it is the right place of handling this kind of logic.
I prefer my reducers to only be responsible for changing state, not for data transformation.
But it is my personal opinion.
We are using a Transformer for transforming the response getting from the Api. Transformer is the function which takes the input and provide the desired output. Designing the transformer makes the code clean and easy to test.
For example :-
function* updateSomethingFlow(action) {
try {
const response = yield call(updateSomething, action.payload);
// after getting the response from the api pass through the transformer.
const transformedResponse =apiTransformer(action.payload);
if (response) {
yield put({
type: UPDATE_SUCCESS,
data: trasnformedResponse
});
}
} catch (error) {
yield put({
type: UPDATE_FAILURE,
error: error)
});
}
}
const apiTransformer = function(apiResponse) {
// implement the logic. This function returns the transformed Response
}
Using this you can move reducer free from the error. Makes the code testable and making mocks easy.
For global backend Errors make a global errorHandler using Redux Middleware, like this
const errorTracking = store => next => action => {
if (/_FAILURE$/.test(action.type)) {
const errorCode = parseInt(
_.get(action, ['error', 'response', 'status'])
)
// this was for my use case
if (errorCode === 403) {
// launch an Global error handler action
return next(ErrorHandlerAction())
} else return next(action)
}
return next(action)
}
While for not genric error You can implement HOC wrap it around the component for visualisation. Thus you can have global implementation for the errors.
I am using mocha and selenium-webdriver for E2E tests. Most of the tests are async and I am using async/await functions to handle this. Unfortunately right now I can't get a single one done. Here is what my code looks like:
describe('Some test', function () {
before(function () {
driver.navigate().to('http://localhost:3000')
})
after(function () {
driver.quit()
})
it('should display element', async function () {
let elementFound = false
try {
await driver.wait(until.elementIsVisible(driver.findElement(By.className('element'))), 1000)
assessForm = await driver.findElement(By.className('element')).isDisplayed()
assert.ok(elementFound)
console.log('elementFound', elementFound)
} catch (err) {
console.log(err)
assert.fail(err)
}
})
})
The problem that is happening seems to be that the after function is being called before the test can finish. Here are the error logs:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
{ NoSuchSessionError: no such session (Driver info:
chromedriver=2.36.540469
(1881fd7f8641508feb5166b7cae561d87723cfa8),platform=Mac OS X 10.13.3
x86_64)
at Object.checkLegacyResponse (/Users/me./myproject/node_modules/selenium-webdriver/lib/error.js:585:15)
at parseHttpResponse (/Users/me./myproject/node_modules/selenium-webdriver/lib/http.js:533:13)
at Executor.execute (/Users/me./myproject/node_modules/selenium-webdriver/lib/http.js:468:26)
at
at process._tickCallback (internal/process/next_tick.js:188:7) name: 'NoSuchSessionError', remoteStacktrace: '' }
If I remove my after() function, I still get
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
but, my console.log shows that my element has been found.
If I then try making after() async, like this:
after(async function () {
await driver.quit()
})
I get the same error as the first one.
It is also important to note that I have read that I don't have to use done() when I am doing async/await. So what in the world is that all about? And even if I did, I keep getting the same error.
How do I solve this? It seems like everything is in order, but I can't seem to appropriately have the tests run through without running into each other.
Instead of using:
await driver.wait(until.elementIsVisible(driver.findElement(By.className('element'))), 1000)
try:
await driver.wait(until.elementLocated(By.className('element'))).isDisplayed()
I have the following code (simplified for this post) - assume an initial call to onStart().
Running this works fine. If I lose the internet connection I get the net::ERR_INTERNET_DISCONNECTED error (as expected) but the polling stops.
Clearly I am not handling any errors here as that is where I'm getting stuck. I'm not clear where I handle those errors and how? Do I need to call startPolling() again?
I need the polling to continue even if there is no internet connection, so that on re-connection data is updated. Any advice please?
onStart() {
this.startPolling().subscribe(data => {
// do something with the data
});
}
startPolling(): Observable<any> {
return Observable
.interval(10000)
.flatMap(() => this.getData());
}
getData() {
var url = `http://someurl.com/api`;
return this.http.get(url)
.map(response => {
return response.json();
});
}
Thanks in advance.
If you know the error happens because of this.http.get(url) then you can add catch() operator that lets you subscribe to another Observable instead of the source Observable that sent an error notification.
getData() {
var url = `http://someurl.com/api`;
return this.http.get(url)
.catch(err => Observable.empty())
.map(response => {
return response.json();
});
}
This will simply ignore the error and won't emit anything.