How to handle response from Express response.write() in Angular $http - angularjs

I'm trying to upload a csv file using ng-file-upoad. Here is my code snippet:
Upload.upload({
url: baseUrl + '/file-upload',
data: {
file: file
}
})
.then(function(res) {
console.log('success: ===> ', res);
}, function(err) {
console.log('erroir: ===> ', err);
}, function() {
console.log('progress: ', arguments);
});
And in node environment I'm parsing the file and inserting the data in database. I don't want to close the connection. That's why I used "response.write". Here is my code snippet:
var path = req.files.file.path,
currentIndex = 0;
fs.readFile(path, 'utf8', function(err, data) {
if(err) {
// handle error
} else {
// making array (dataArray) from data
dataArray.forEach(function(eachData){
newEntry = new app.db.models.SomeCollection(eachData);
newEntry.save(function(err, data) {
if (currentIndex === dataArray.length) {
res.end('DONE!');
} else {
currentIndex++;
res.write(JSON.stringify({
total: dataArray.length,
done: currentIndex
}));
}
});
})
}
});
My question is how I will get the data I'm passing in "res.write"? I don't want to use socket for only this purpose. Am I missing something?

As already explained here:
response.send(msg) is equal to response.write(msg);response.end();
Which means, send can only be called once, write can be called many times, but you must call end yourself.
You are probably not receiving the response because response.end() is missing.
Once you end() your response you should be able to access the response data in your angular controller in the Upload.upload promise that is returned.
It's not like close a connection as you said. This is not a socket-ish like implementation (such as ws or socket.io). Once a request is made it should have a response even if it is to provide error details about that request (i.e. status 401, 403, 404, etc).

in your angular component:
...
constructor(private incrementalService: IncrementalService) {}
incrementalTest() { //activate with a button or whatnot
this.incrementalService.increment().subscribe( (result:any) => {
if (result.partialText) {
console.log(partialText); //do whatever you need to do with your partial results here!
}
})
}
your angular service:
import { HttpClient, HttpHeaders } from '#angular/common/http';
public class IncrementalService {
constructor(private http: HttpClient) {}
increment(): Observable<ArrayBuffer> {
const options = {
reportProgress: true,
responseType: 'text',
observe: 'events'
}
return this.http.request('get', 'http://someURL', { ...this.addRawHeaderOptions(), ...options});
}
private addRawHeaderOptions() {
const authHeaders = new HttpHeaders({
'Content-Type': 'application/json',
//authorization, Cache-Control: 'no-cache, Pragma:'no-cache', et al. }
return { headers: authHeaders }
}
}
Finally, your back-end service (this is express, but should work similarly for raw node):
async function(request, response) {
const increments = [ 1,2,3,4 ];
response.set('Content-Type', 'text/html');
for (const value of increments) { //contains async call - not switch-outable for a forEach.
response.write(`increment - ${value} `);
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
await delay(1000)
}
response.status(200).end()
}
browser console output when run:
increment - 1
increment - 1 increment - 2
increment - 1 increment - 2 increment - 3
increment - 1 increment - 2 increment - 3 increment - 4
!!Sorry for any typos - i had to transcribe this from a locked-down machine.

Related

React Chrome extension and Promises

I am writing a Chrome extension in ReactJS.
I am looping through an array of URLs and trying to get the the HTML content of those pages.
this.state.advertData.map(function(e, i) {
common.updateTabUrl(e.url).then((tab) => {
common.requestHTML(tab).then((response) => {
console.log(response.content);
})
});
})
common.js:
let requestHTML = function(tab) {
return new Promise(function(resolve, reject) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tab.id, {'req': 'source-code'}, function (response) {
resolve(response)
})
})
})
}
let updateTabUrl = function(url) {
return new Promise(function(resolve, reject) {
let update = chrome.tabs.update({
url: url
}, function(tab) {
chrome.tabs.onUpdated.addListener(function listener (tabId, info) {
if (info.status === 'complete' && tabId === tab.id) {
chrome.tabs.onUpdated.removeListener(listener);
resolve(tab);
}
});
})
})
}
content_script.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
let response = '';
if (request.req === 'source-code') {
response = document.documentElement.innerHTML;
}
sendResponse({content: response});
});
My issue is that the response.content always seems to be the same. More importantly, the tab that updates seems to only ever display the last url in my array. I think it is a problem with the way I am handling Promises.
Any help is appreciated.
The problem with your code is that it doesn't wait for the previous URL to load before proceeding to the next one so only the last one gets actually loaded in a tab.
I suggest using 1) Mozilla's WebExtension polyfill, 2) await/async syntax, 3) executeScript that automatically runs when a tab is complete by default 4) a literal code string in executeScript so you don't need neither a separate file nor to declare the content script in manifest.json.
async function getUrlSourceForArray({urls, tabId = null}) {
const results = [];
for (const url of urls) {
await browser.tabs.update(tabId, {url});
const [html] = await browser.tabs.executeScript(tabId, {
code: 'document.documentElement.innerHTML',
});
results.push(html);
}
return results;
}
Invoking inside an async function:
const allHtmls = await getUrlSourceForArray({
urls: this.state.advertData.map(d => d.url),
tabId: null, // active tab
});
P.S. you can also open all the URLs at once in a new window in background, assuming there won't be more than say 10 URLs, otherwise you would risk exhausting the user's RAM.

throw new ERR_INVALID_ARG_TYPE('chunk',['string','Buffer'],chunk);TypeError[ERR_INVALID_ARG_TYPE]:The "chunk" arg must be type string or Buffer

I am trying to get the contents of a .json file using a node js service into an angularjs method. But am getting following error:
_http_outgoing.js:700
throw new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be one of type string or Buffer. Received type object
at ServerResponse.end (_http_outgoing.js:700:13)
here are the corresponding code fragments...
angular controller: the commented lines are all of those which i have tried and failed with.
var currentProcess = "process_1cA";
$scope.storestats = [];
var resAss = $resource('/procs/getstorestats');
var stats = resAss.get({
process: currentProcess,
date: date.getFullYear() + "" + m + "" + d
});
stats.$promise.then(function(response) {
if (response != undefined) {
// var r = JSON.parse(response);
//$scope.storestats.push(r);
//$scope.storestats.push(r);
//var r = JSON.parse(response);
$scope.storestats.push(response);
//angular.forEach(r, function(value, key) {
// $scope.storestats.push({key : value});
//});
}
});
NODEJs service:
httpApp.get('/procs/getstorestats', function(req, res, next) {
try {
fs.readFile(cfg.routestatspath + "storestats-"+req.query.process + "-" + req.query.date + ".json", function (err, data) {
var msgs1 = JSON.parse(data);
//var r = data.toString('utf8');
var msgs2 = JSON.stringify(msgs1);
console.log(msgs1);
res.end(msgs1);
});
}
catch (err) {
res.end(err.toString());
}});
P.S: The commented out lines are those which i have tried out with and failed. Also, the commented lines in the node service code snippet, give no error, and when logged show it correctly, but the data when in response of the controllers is blank.
I'm guessing a bit here, but I think you just need to change res.end() to res.send() in your Node code. The "end" method is used when you are streaming chunks of data and then you call end() when you're all done. The "send" method is for sending a response in one go and letting Node handle the streaming.
Also, be sure you are sending a string back!
httpApp.get('/procs/getstorestats', function(req, res, next) {
try {
fs.readFile(cfg.routestatspath + "storestats-"+req.query.process + "-" + req.query.date + ".json", function (err, data) {
var msgs1 = JSON.parse(data);
//var r = data.toString('utf8');
var msgs2 = JSON.stringify(msgs1);
console.log(msgs1);
res.send(msgs2); // NOTE THE CHANGE to `msg2` (the string version)
});
}
catch (err) {
res.send(err.toString()); // NOTE THE CHANGE
}
});
I had a similar error. It was because I was passing process.pid to res.end(). It worked when I changed process.pid to string
res.end(process.pid.toString());
Figured it out. 2 small changes were needed.. One in the controller, which was to use a "$resource.query" instead of "$resource.get". And in the service, as #jakarella said, had to use the stringified part in the .end();
Controller:
var resAss = $resource('/procs/getstorestats');
var stats = resAss.query({process: currentProcess, date: date.getFullYear() + "" + m + "" + d});
stats.$promise.then(function (response) {
$scope.storestats.push(response);
}
Node Service:
httpApp.get('/procs/getstorestats', function(req, res, next) {
try {
fs.readFile(cfg.routestatspath + "storestats-"+req.query.process + "-" + req.query.date + ".json", function (err, data) {
var msgs1 = JSON.parse(data);
var msgs2 = JSON.stringify(msgs1);
console.log(msgs2);
res.end(msgs2);
});
}
If you are using 'request-promise' library set the json
var options = {
uri: 'https://api.github.com/user/repos',
qs: {
access_token: 'xxxxx xxxxx'
},
headers: {
'User-Agent': 'Request-Promise'
},
json: true // Automatically parses the JSON string in the response
};
rp(options)
.then(function (repos) {
})
.catch(function (err) {
});
Thank you user6184932, it work
try {
await insertNewDocument(fileNameDB, taskId);
res.end(process.pid.toString());
} catch (error) {
console.log("error ocurred", error);
res.send({
"code": 400,
"failed": "error ocurred"
})
}
in mysql2 the reason for the error is the sql word , sql is a query :
const sql = select * from tableName
pool.executeQuery({
sql,
name: 'Error list for given SRC ID',
values: [],
errorMsg: 'Error occurred on fetching '
})
.then(data => {
res.status(200).json({ data })
})
.catch(err => {
console.log('\n \n == db , icorp fetching erro ====> : ', err.message, '\n \n')
})
I got the error using Node v12 (12.14.1).
Uncaught TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be one of type string or Buffer. Received type number
Sample code for context.
const { Readable } = require('stream')
Readable.from(Buffer.from(base64content, 'base64'))
.pipe( ... )
Solution (for my case), was upgrading to Node v14 (14.17.3). e.g.
nvm use 14
nvm

How to Run an API Calls in Parallel (Node.js)

I am trying to run some API calls in parallel, but am having problems since I am trying to call a function again before the API data has been returned.
I am thinking that I could possibly use the new command in Node, but am not sure how to structure it into this scheme. I am trying to avoid recursion, as I already have a recursive version working and it is slow.
Currently I am trying to this code on the server.
loopThroughArray(req, res) {
for(let i=0; i<req.map.length; i++) {
stack[i] = (callback) => {
let data = getApi(req, res, req.map[i], callback)
}
}
async.parallel(stack, (result) => {
res.json(result)
})
}
....
function getApi(req, res, num, cb) {
request({
url: 'https://example.com/api/' + num
},
(error, response, body) => {
if(error) {
// Log error
} else {
let i = {
name: JSON.parse(body)['name'],
age: '100'
}
console.log(body) // Returns empty value array.length > 1 (req.map[i])
cb(i)
}
})
Is there a way to spawn new instances of the function each time it's called and accumulate the results to send back as one result to the client?
Here's an example of calling Web APIs (each with different parameters), using the Async library, we start by creating an array of N function variables.
const async = require('async');
const request = require('request');
//Set whatever request options you like, see: https://github.com/request/request#requestoptions-callback
var requestArray = [
{url: 'https://httpbin.org/get'},
{url: 'https://httpbin.org/ip'}
];
let getApi = function (opt, callback) {
request(opt, (err, response, body) => {
callback(err, JSON.parse(body));
});
};
const functionArray = requestArray.map((opt) => {
return (callback) => getApi(opt, callback);
});
async.parallel(
functionArray, (err, results) => {
if (err) {
console.error('Error: ', err);
} else {
console.log('Results: ', results.length, results);
}
});
You can easily switch the Url and Query values to match whatever you need. I'm using HttpBin here, since it's good for illustrative purposes.

ionic 3 acces to json key

i can't access to a key of a json response from a restful web service.
{"_body":"{\"values\": {\"user_id\":\"1\",\"name\":\"fred test\",\"email\":\"fred#test.test\",\"username\":\"fredtest\",\"token\":\"d5f66a06ec809d70d0c52842df8dc0011d7d1ad0f2d56f50d3123da17a2489fe\"}}","status":200,"ok":true,"statusText":"OK","headers":{"pragma":["no-cache"],"content-type":["text/html;charset=UTF-8"],"cache-control":["no-store"," no-cache"," must-revalidate"],"expires":["Thu"," 19 Nov 1981 08:52:00 GMT"]},"type":2,"url":"http://localhost/PHP-Slim-Restful/api/login"}
I would like to acces to 'values' in this function: (this.responseData.values)
login(){
console.log('login'+ this.userData);
// Your app login API web service call triggers
this.authService.postData(this.userData,'login').then((result) => {
this.responseData = result;
console.log('userdata : '+ temp);
if(this.responseData.values){
console.log('response: ' + this.responseData);
localStorage.setItem('userData', JSON.stringify(this.responseData));
this.navCtrl.push(TabsPage);
}
else{
this.showToastWithCloseButton()
}
}, (err) => {
console.log('erreur : '+err);
});
}
I have an error undifined!
Can you help me?
I have used Observable to return json data and using the subscribe function in my method and using response.json() to convert the JSON reponse from RESTful webservices.
My component method,
import {Http, Headers, Response, RequestOptions} from '#angular/http';
import {Observable} from 'rxjs/Rx';
var response = this.service.post('deleteUserDetails/'+this.selectedUserId, null);
response.subscribe((res) => {
var response = res.json();
});
Service Post method,
post(url: string, data : any): Observable<any> {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers});
return this.http.post(url, data,{headers: headers});
}
I think this might be helpful for your query.
You can make a for in your JSON and access the return values of your post. Something like that.
"this.responseData = result.json();" -> Return JSON. Make a for.
Example:
public postData(data, url: string) {
this.http.post(url, data).toPromise().then(res => {
let responseData = res.json();
if (responseData) {
for (var item of responseData) {
//Implments
}
}
}, (err) => {
});
}

Create and Update JSON calls not working

I am learning Angular 2 and have an interesting issue. I am using json-server to mock my service calls and retrieve works well. However I have issues with Create and Update.
I am using a basic model called notification which looks like so:-
export class NotificationModel {
constructor(
public id: number,
public name: string,
public description: string
){}
}
and here's my basic functions nothing too strange here!
createNotification(notification : NotificationModel) {
return this._http.post('http://{myurl}/notifications', JSON.stringify(notification))
.map(res => res.json());
}
updateNotification(notification : NotificationModel) {
return this._http.put('http://{myurl}/notifications/' + notification.id, JSON.stringify(notification))
.map(res => res.json());
}
When I try to pass in simple test values I instead get the following:-
The create generates a 9 character alphanumeric value for id and nothing in the other fields.
Here's my object:-
{"id":5,"name":"NEW NOTIFICATION","description":"NEW NOTIFICATION DESCRIPTION"}
UPDATE:- Here's what it creates
{
"id": "rkxCLjZLx"
}
The update blanks out the other two fields and just keeps the id field.
Here's my object
{"id":"3","name":"Notification 3","description":"UPDATE DESCRIPTION"}
UPDATE:- Here's the record after update
{
"id": "3"
}
Is this a json-server issue or is there something obvious that I'm doing wrong?
UPDATE
Here's the functions I use to call my service
addNotification(notification : NotificationModel) {
this._notificationService.createNotification(new NotificationModel(5,
'NEW NOTIFICATION', 'NEW NOTIFICATION DESCRIPTION')).subscribe(
data => {
// refresh the list
this._notificationService.getNotifications().subscribe(res => {
this.notifications = res;
}
);
return true;
},
error => {
console.error("Error adding notification!");
return Observable.throw(error);
}
);
}
updateNotification(notification : NotificationModel) {
notification.description = 'UPDATE DESCRIPTION';
this._notificationService.updateNotification(notification).subscribe(
data => {
// refresh the list
this._notificationService.getNotifications().subscribe(res => {
this.notifications = res;
}
);
return true;
},
error => {
console.error("Error updating notification!");
return Observable.throw(error);
}
);
}
Found my issue!
I wasn't setting the content type anywhere! By updating my PUT and POST requests like so it now works as expected.
createNotification(notification : NotificationModel) {
let body = JSON.stringify(notification);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.post(this.serviceURL, body, options)
.map(res => res.json());
}
updateNotification(notification : NotificationModel) {
let body = JSON.stringify(notification);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.put(this.serviceURL + '/' + notification.id, body, options)
.map(res => res.json());
}

Resources