Delete Request with params MongoDB NodeJS - javascript

I try to send delete request from Angular 4 to mongoDb
I have an array of ids, which I want to delete and in my service I have a function
deleteData(id) {
return this.http.delete( this.api, id)
}
Then in my component I build an array of objects (because I need to pass it to backend as JSON - as an array it won't be probably recognised)
deleteData(data) {
const dataToSend = [];
let oneDataToSend;
for (let i = 0; i < data.length; i++) {
oneDataToSend = {'_id': ''};
oneDataToSend._id = data[i];
dataToSend.push(oneDataToSend);
}
this.service.deleteData(dataToSend).subscribe((res) => {
console.log(data);
});
}
And after that I try to delete objects, which ids are the same as in a query
app.delete('/tasks', function(req,res){
console.log(req.body);
var ids = [];
for (let i = 0; i < req.body.length; i ++) {
ids.push(req.body[i]._id);
}
var myquery = { _id: { $in: ids } };
Model.collection.deleteMany(myquery, function(err, obj) {
if (err) throw err;
});
});
Here I got the problem, that there req.body is empty {}
Also, in console in Network section I see 2 requests
OPTIONS (with Status Code 204 No Content)
DELETE without any info
Could you please give me a hint and help to solve this problem?

The reason you see the OPTIONS request with a 204 NO CONTENT response is because of Cross Origin Resource Sharing (CORS). The client is checking if it is allowed to make a DELETE request to your backend.
Consider allowing CORS in the backend application. For an easy way for express, use expressjs/cors. However, make sure you understand the security implications of allowing cross-site requests.
Also, are you parsing the request body? If not, it will be undefined in req.body.
You can use express.json(), it will attempt to parse the JSON of the request body and save it to req.body, but only if the header "Content-Type: application/json" is sent along with the request:
const app = express();
app.use(express.json()); // Parses request body if type is json. Saves to req.body.

Related

How to find how much bytes were sent on fetch request?

I am fetching data from different API with javascript's fetch API. But how can I find out how many bytes are sent on each request for analytics?
The request could be in any method.
I know that I can get the amount of bytes received with
response.headers["content-length"].
I need to find out a way to get the amount of bytes sent on the frontend (browser or mobile using React Native). Ideally, it would be the total size of the request, but just the size of the request body would be good enough.
You can get the value that will be set in the Content-Length header by reading the Request's body as text and checking the length of the returned string:
(async () => {
const formdata = new FormData();
const file = new Blob(["data".repeat(1024)])
formdata.append("key", file)
const req = new Request("/", { method: "POST", body: formdata });
// note that we .clone() the Request
// so that we can still use the original one with fetch()
console.log((await req.clone().text()).length);
fetch(req);
console.log("check the Network panel of your dev tools to see the sent header");
})();
However this only applies for requests where this header is sent, i.e not for GET and HEAD requests.
A quick solution that I used - a tiny middleware (I use Express):
const socketBytes = new Map();
app.use((req, res, next) => {
req.socketProgress = getSocketProgress(req.socket);
next();
});
/**
* return kb read delta for given socket
*/
function getSocketProgress(socket) {
const currBytesRead = socket.bytesRead;
let prevBytesRead;
if (!socketBytes.has(socket)) {
prevBytesRead = 0;
} else {
prevBytesRead = socketBytes.get(socket).prevBytesRead;
}
socketBytes.set(socket, {prevBytesRead: currBytesRead})
return (currBytesRead-prevBytesRead)/1024;
}
And then you can use req.socketProgress in your middlewares.

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client (multiple data entries)

So I was trying to INSERT then UPDATE data, database was successfully updating based on the intended queries and was able to receive the response to the client but getting the error above on the server, not sure how to debug it, I've tried to look with the previous related questions with no luck.
var urlencodedParser = bodyParser.urlencoded({ extended: false });
router.post('/createprovision', urlencodedParser,(req, res) => {
let serials = [];
for (let i = 0; i < req.body.length; i++){
serials.push(req.body[i][1]);
}
let sql = 'INSERT INTO provision (employee_id, serial_no, provision_date) VALUES ?';
connection.query(sql, [req.body],(err, results) => {
for(let i = 0; i < serials.length; i++){
let sql2 = `UPDATE inventory SET ? WHERE serial_no = '${serials[i]}'`;
connection.query(sql2, [{status: "assigned"}],(err, results) => {
if (err) throw err;
return res.send("provision success!");
});
}
});
});
ERR_MSG :
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent
to the client (multiple data entries)
You've put your return res.send("provision success!"); inside a for-loop which means you send a response to the client in your first iteration, then you are attempting to send response again but the headers were already sent. Place it at the end of your function, sending the response only after your process all serials.

NodeJS Undefined JSON object

just posting a question as I have seen some other similar questions on here but none with a method that seemingly works for me.
I'm new to NodeJS and playing around with requesting data from an API. For my test here im just trying to pull ticker prices based on the input of a prompt from the user.
This works fine, however the object
This is the code I am using to try and make this work:
prompt.start();
prompt.get(['coin'], function (err, result) {
request({url: `https://min-api.cryptocompare.com/data/price?fsym=${result.coin}&tsyms=BTC,USD`, json:true}, function(err, res, json) {
if (err) {
throw err;
}
console.log(json);
var json = JSON.stringify(json);
var string2 = JSON.parse(json);
console.log(string2.btc_price);
console.log(json);
});
console.log('Retrieving: ' + result.coin);
});
The API request works, however it returns JSON that looks like this with my 3 console logs:
{ set_attributes: { btc_price: 1, usd_price: 15839.35 } }
undefined
{"set_attributes":{"btc_price":1,"usd_price":15839.35}} -- (Stringify'd response)
I want to be able to extract the btc_price & usd_price as variables, ive tried a few different methods and can't figure out where exactly im going wrong. Any help would be greatly appreciated!
Cheers,
J
When you attempt to extract the btc_price attribute, it's actually nested so your second console should read console.log(string2.set_attributes.btc_price);
axios has more stars on Github, more followers on Github and more forks.
Features
Make XMLHttpRequests from the browser
Make http requests from node.js
Supports the Promise API
Intercept request and response
Transform request and response data
Cancel requests
Automatic transforms for JSON data
Client side support for protecting against XSRF
Using async / await
// Make a request for a user with a given ID
var preload = null;
async function getPrice(symbol) {
preload = await axios.get('https://min-api.cryptocompare.com/data/price?fsym=${symbol}&tsyms=BTC,USD')
.then(function (response) {
preload = response.data;
})
.catch(function (error) {
console.log(error);
});
return `preload.BTC = ${preload.BTC}; preload.BTC = ${preload.BTC}`;
};
getPrice('ETH');
// return preload.BTC = 0.04689; preload.USD = 742.85

node express.js Can't set headers after they are sent.'

I am new to both node and express so I figure I am doing something stupid.
Complete source code can be found at:
https://github.com/wa1gon/aclogGate/tree/master/server
logRouter.get("/loggate/v1/listall", function(req, res) {
let countStr = req.param('count');
let count: number;
if (!countStr) {
count = null;
} else {
count = Number.parseInt(countStr);
if (count == NaN) count = null;
}
acConn.listAllDatabase(count, (err: string, result: Array<LogGateResp>) => {
console.log("got list all data resp")
return res.json(result).end();
});
}
);
app.use('/', logRouter);
It works the first time though, but blows up the second.
listallDatabase connects to a network socket which gets XML database back, parses it and calls back with an JS object. Which in turn calls res.json.
Suggestions?
Remove the end() after res.json().
res.josn() send the response to frontend and end() try to send the response again.
That why you are getting the error. Because node.js don't allow the API to send response twice. Either use res.end() or res.json().

Duplicate chunks on JSON response

I've got a fairly standard MEAN project setup with the angular-fullstack generator using yeoman.
What I'm finding is that when GETting a largish (over 65536 bytes) json result, it is encoded using gzip and chunked, but the json returned is not valid viewed either in chrome or consumed by my angular client $resource because it contains TWO responses!
e.g {name:'hi'}{name:'hi'} for a single id or [{..},{..}][{..},{..}] for a array.
The server api endpoint was autogenerated from the angular-fullstack generator and looks something like:
// Get list of worlds
exports.index = function(req, res) {
World.find(function (err, worlds) {
if(err) { return handleError(res, err); }
res.json(200, worlds);
});
};
If i slice the data so it's not chunked, then the json is well formed. I've checked the mongo db and the data is ok there too and debugging the worlds variable, I can JSON.stringify and get the expected string result without any duplicates. but the moment it's sent, I'm getting a doubling up of json result on the response.
Update for comment
angular-fullstack 2.0.4
the schema looks like:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var WorldSchema = new Schema({
name: String,
info: String,
active: Boolean,
tiles: [Schema.Types.Mixed]
});
module.exports = mongoose.model('World', WorldSchema);
seeded with:
var newWorld = new WorldModel({
_id: planet._objectId,
name: "SimDD World",
tiles : seed()
});
newWorld.save();
...
var seed = function () {
var data = [];
for (var i = 0; i < planet.HEIGHT; i++) {
for (var j = 0; j < planet.WIDTH; j++) {
data.push({
coords:{
x:i,
y:j
},
type:'.'
});
}
}
return data;
}
Looks like this is being caused by the compression middleware, removing app.use(compression()); from the express config seems to fix this.
The issue is seen in browsers and not in postman. I checked the HTTP request headers and when I add 'Accept' Header as html in postman the same problem is seen in postman as well. So I believe the browsers are handling differently with Accept type with html.
// app.use(require('connect-livereload')());
I came across the same problem when building my angular-fullstack app (thanks, DaftMonk), after some extensive debugging using node-inspector, turns out the JSON data gets passed to the livereload module and gets duplicated when it comes out. Disabling this middleware eliminated the problem for me.
Does this work for you? I don't see a reason why it shouldn't.
I assume you have a planet object that has:
HEIGHT, WIDTH and _objectId properties.
Remember if you modify a mixed type you need to tell mongoose
that the value changed and subsequently save it.
http://mongoosejs.com/docs/schematypes.html#mixed
var WorldModel = require('../api/world/world.model');
var planet = require('planetSeedData');
var seed = function() {
var data = [];
for (var i = 0; i < planet.HEIGHT; i++) {
for (var j = 0; j < planet.WIDTH; j++) {
data.push({
coords: {x:i, y:j},
type: '.'
});
}
}
return data;
};
var myPlanet = {
_id: Mongoose.Types.ObjectId(planet._objectId),
name: "SimDD World",
tiles : seed()
};
WorldModel.create(myPlanet);
// if modified, you would do something like:
// WorldModel.markModified('tiles');
// WorldModel.save();

Categories