The problem is that you are running multiple requests to save the file at the same time.
Save A arrives and async loads the file - during which time Save B arrives and loads before Save A has committed its change.
The solution is to run only one of these save requests at a time - something like this (which I've not tested) that keeps an array of save functions and chunks through them in sequence of arriving:
// an array of functions in the queue
var fnBuffer = []
// are we currently running a function in the queue
var running = false
// run the queue one at a time - on finish run again
function runSave(){
if(running) return
running = true
var nextfn = fnBuffer.shift()
if(!nextfn) return
nextfn(function(){
running = false
runSave()
})
}
exports.saveIngredient = function(req, res) {
// push the function onto the queue
fnBuffer.push(function(callback){
// this is the original code - the only extra is the callback
var ing = req.body;
console.log('Saving Ingredient: ' + JSON.stringify(ing, null, 4));
fs.readFile('./data/data.json', 'utf-8', function (error, data) {
var mData = JSON.parse(data);
ing.id = generateId(ing.name, mData.ingredients);
mData.ingredients.push(ing);
fs.writeFile('./data/data.json', JSON.stringify(mData, null, 4), function(err) {
res.writeHead(200, { 'Content-Type': 'text/json' });
res.end(ing.id, 'utf-8');
// running this callback tells the queue to run the next function
callback()
});
});
})
// trigger the queue
runSave()
};