Reputation: 13482
I am trying to build an api from the braintree servers. Referring to this doc https://developers.braintreepayments.com/javascript+node/reference/general/result-handling/search-results
To access all the transactions from their server I have to return a node stream.
ex
app.get('/project', function(req, res) {
if(req.user) {
var stream = gateway.transaction.search(function (search) {
search.customerId().is(req.user.id);
});
stream.on("ready", function () {
console.log(stream.searchResponse);
});
stream.on("data", function (data) {
res.json(data) // can't set headers after they are sent.
});
}
});
I understand a stream returns data in chunks, so the res.json()
above is most likely is being called multiple times resulting in Error: Can't set headers after they are sent
.
So my question is how can I send that data to the client in one chunk? The nodejs streaming is confusing to me, I am going to read up more about it, but it would be great to understand how to send the data to the client without re-sending the headers.
Upvotes: 1
Views: 2397
Reputation: 106746
You shouldn't make any assumptions about data
events unless the stream you are reading from is in object mode. You could get one data
event or a hundred (depending on the input size of course) because TCP is a stream.
What you probably want is something like this instead (assuming stream
is not in object mode):
app.get('/project', function(req, res) {
if(req.user) {
var stream = gateway.transaction.search(function (search) {
search.customerId().is(req.user.id);
});
stream.on("ready", function () {
console.log(stream.searchResponse);
});
var buf = '';
stream.on("data", function (data) {
buf += data;
});
stream.on("end", function() {
res.setHeader('Content-Type', 'application/json');
res.send(buf);
});
}
});
Or just pipe the stream to the response:
app.get('/project', function(req, res) {
if(req.user) {
var stream = gateway.transaction.search(function (search) {
search.customerId().is(req.user.id);
});
stream.on("ready", function () {
console.log(stream.searchResponse);
});
res.setHeader('Content-Type', 'application/json');
stream.pipe(res);
}
});
For an object stream you might do:
app.get('/project', function(req, res) {
if(req.user) {
var stream = gateway.transaction.search(function (search) {
search.customerId().is(req.user.id);
});
stream.on("ready", function () {
console.log(stream.searchResponse);
});
var result = [];
stream.on("data", function (data) {
result.push(data);
});
stream.on("end", function() {
res.json(result);
});
}
});
Upvotes: 6