angular2-rc1 http.post not working correctly - node.js

I am creating one angular2 app in which I am using http in my service to make POST call to mongoDB.
When I am making a POST call for the first time it is working fine i.e. entry is inserted into database correctly but when I am sending the data for second time it is not getting inserted.
If I am reloading the page after first insertion then its working fine.
I did some debugging and found that during second request my req.body is blank.
Here is my code:
page.service.ts
savePage(page: Object) {
this.headers.append('Content-Type', 'application/json');
let url = this.baseUrl+'/pm/pages/';
let data={};
data["data"]=page;
console.log(data); //this is printing both times correctly
//on second request data is blank where as it works correctly for first time
return this.http.post(url, JSON.stringify(data),{headers: this.headers})
.map((res: Response) => res.json()).catch(this.handleError);
}
Here is my data in req.body shown in node services.
First Request:
body:{
data:{
name: 'wtwetwet',
desc: 'wetwetwetetwte',
isPublic: true,
createdBy: 'Bhushan'
}
}
Second Request
body: {}
any inputs?

It looks more like a backend thing. You should however include the code that subscribes on this http call.
By the way, why are you using RC1? Angular 2 is now on RC5.

I finally realised that my method used to set content-type each time it was getting called.
Thus changing code from :
savePage(page: Object) {
this.headers.append('Content-Type', 'application/json');
let url = this.baseUrl+'/pm/pages/';
let data={};
data["data"]=page;
return this.http.post(url, JSON.stringify(data),{headers: this.headers})
.map((res: Response) => res.json()).catch(this.handleError);
}
to:
savePage(page: Object) {
this.headers=new Headers();
this.headers.append('Content-Type', 'application/json');
let url = this.baseUrl+'/pm/pages/';
let data={};
data["data"]=page;
return this.http.post(url, JSON.stringify(data),{headers: this.headers})
.map((res: Response) => res.json()).catch(this.handleError);
}
did the trick for me.
Actually we need to set headers only once while making a rest call,but in my code it was already set thus creating new Headers Object helped me clearing any previously set configurations.
Thanks for the help guys.

Related

fetch returns empty body, json works, but plain text doesn't

I am trying to create a function which return the latest blocked domain from my pihole server.
I first created a JSON call, since the first call I needed was in JSON format, this is all working and I get the data needed.
However, the second function I need is to fetch plain text data and that one doesn't work, it simply returns an empty body [].
This is the function
socket.on("pihole_last", function() {
setInterval(function() {
let settings = {
method: "Get",
headers: {
"Accept": "text/html"
}
};
fetch('http://domain/admin/api.php?recentBlocked', settings)
.then(res => res.text())
.then((data) => {
console.log(data);
}).catch(error => {
return error;
});;
}, 1000)
});
The JSON function which works looks pretty much the same, the only real different is the header accept and the res.text() which should fetch the data in plain text?
The data returned from the URL is a plain text domain, no tags, no nothing.
According to this issue from the pi-hole GIT, you should provide some form of authentication. The question which you linked in your comment is 5 years old, at that time this was an unintended behaviour.
If I understand correctly the API description one way to authorize should be working with this url:
http://domain/admin/api.php?recentBlocked?auth=YOUR_TOKEN
The YOUR_TOKEN should be in:
Authorization & Token required (see WEBPASSWORD in /etc/pihole/setupVars.conf)

Axios request with chunked response stream from Node

I have a client app in React, and a server in Node (with Express).
At server side, I have an endpoint like the following (is not the real endpoint, just an idea of what i'm doing):
function endpoint(req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain',
'Transfer-Encoding': 'chunked'
});
for(x < 1000){
res.write(some_string + '\n');
wait(a_couple_of_seconds); // just to make process slower for testing purposes
}
res.end();
}
This is working perfect, i mean, when I call this endpoint, I receive the whole stream with all the 1.000 rows.
The thing is that I cannot manage to get this data by chunks (for each 'write' or a bunch of 'writes') in order to show that on the frontend as soon as i'm receiving them..(think of a table that shows the rows as soon as i get them from the endpoint call)
In the frontend I'm using Axios to call the API with the following code:
async function getDataFromStream(_data): Promise<any> {
const { data, headers } = await Axios({
url: `http://the.api.url/endpoint`,
method: 'GET',
responseType: 'stream',
timeout: 0,
});
// this next line doesn't work. it says that 'on' is not a function
data.on('data', chunk => console.log('chunk', chunk));
// data has actually the whole response data (all the rows)
return Promise.resolve();
}
The thing is that the Axios call returns the whole data object after the 'res.end()' on the server is called, but I need to get data as soon as the server will start sending the chunks with the rows (on each res.write or whenever the server thinks is ready to send some bunch of chunks).
I have also tried not to use an await and get the value of the promise at the 'then()' of the axios call but it is the same behavior, the 'data' value comes with all the 'writes' together once the server does the 'res.end()'
So, what I doing wrong here ? maybe this is not possible with Axios or Node and I should use something like websockets to solve it.
Any help will be very appreciate it because I read a lot but couldn't get a working solution yet.
For anyone interested in this, what I ended up doing is the following:
At the Client side, I used the Axios onDownloadProgress handler that allows handling of progress events for downloads.
So, I implemented something like this:
function getDataFromStream(_data): Promise<any> {
return Axios({
url: `http://the.api.url/endpoint`,
method: 'GET',
onDownloadProgress: progressEvent => {
const dataChunk = progressEvent.currentTarget.response;
// dataChunk contains the data that have been obtained so far (the whole data so far)..
// So here we do whatever we want with this partial data..
// In my case I'm storing that on a redux store that is used to
// render a table, so now, table rows are rendered as soon as
// they are obtained from the endpoint.
}
}).then(({ data }) => Promise.resolve(data));
}

How to send Object by Post request using native Ajax on NodeJS

I am trying to POST the input filed value as an object to the NodeJs controller. Here i am using native ajax POST method. And body-parser package on nodejs to access the POST request. But when i log the res.body i see its empty. I am new in Ajax and NodeJs. Sorry if i am making any obvious mistakes...
window.addEventListener("load" , () => {
let formSubmit = document.querySelector("#formSubmit");
formSubmit.addEventListener("submit", (e) => {
e.preventDefault();
let inputTodo = document.querySelector("#inputTodo").value;
let todo = {item : inputTodo};
let xhr = new XMLHttpRequest();
xhr.open("POST" , "/todo" , true);
xhr.setRequestHeader("Content-type", "application/json");
let data = todo;
console.log(data)
xhr.send(data);
location.reload();
})
});
app.post("/todo" ,urlencodedParser, (req, res) => {
console.log(req.body)
data.push(req.body);
res.json(data);
})
Looks like you are sending and undefined data object, for what i see in your code you never assign any value to the data variable before call the .send(data) method. So try with this and should work
xhr.send({id: 'example_id'});
Defining the method in template engine form as POST solved the problem for me. It's a GET method by default but somehow when we are using the jQuery Ajax we don't need to change the method. And it works fine. But if we want to use Native Ajax we must set the POST method in the form even when we are defining the type as POST.
form(
method="POST"
action="/Contact"
)

How can response header can be modified?

i have a problem that break my mind since 2 days.
request( {url: url } , function(err,res, body){ res.headers['...'] = ...; return res }).pipe(response);
I thought this code change the header from the first response then put him on the second response. but NOT, all attempt fail. I try and I try but NOTHING, NOTHING WORKK.
Look, I'm really in peace and open-minded.
that's my code clear and concise :
modify_header(err,res,body){
var header = res.headers;
header['x-frame-options'] = null;
header['Set-Cookie'] = 'HttpOnly;';
return res;
}
request_src(req,response){
let isabsolute = this.decode_href(req.url);
if(!isabsolute) {
request.get({ url : this.url+req.url , headers : this.headers },this.modify_header).pipe(response);
}else{
request.get({ url : isabsolute , headers : this.headers },this.modify_header).pipe(response);
}
return false;
}
request_src(req,response) is a function called in http.createServer so, req & response are just the request from clients.
then, when i do request.get( {url:this.url ... I send client's request to an another site, like a proxy. but i need to change the header between the "other site" and the client. and believe me for sure, function modify_header modify nothing.
no, i lie just a little, when i set header['x-frame-options'] = null;res.headers is equals to null. that's ok
BUT, in the browser (client side) It just doesn't work that way. 'x-frame-options' is deny or something that's not mine (the same for cookie).
can you help me please, I pull out my hair since 2 days and this isn't good for me.
thank you.
The issue is that callbacks actually happen after a request is complete, which is way after the pipe has already begun streaming data to the response. You probably want to hook into the response event, which would look something like this:
request.get({ url: this.url + req.url, headers: this.headers })
.on('response', function (resp) {
resp.headers['my-custom-header'] = 'blah';
})
.pipe(response);
The response event is emitted before streaming to the destination (which in this case, is back to the original caller), so you should be able to do what you want using this method.
my code looks like that right now :
modify_header(res){
var header = res.headers;
header['x-frame-options'] = null;
header['Set-Cookie'] = 'HttpOnly;';
return res;
}
request_src(req,response){
console.log('original: ',req.url);
let isabsolute = this.decode_href(req.url);
if(!isabsolute) {
request.get({ url : this.url+req.url , headers : this.headers })
.on('response',this.modify_header)
.pipe(response);
}else{
request.get({ url : isabsolute , headers : this.headers})
.on('response',this.modify_header)
.pipe(response);
}
return false;
}

HttpClientModule http.get not working

I picked up this previous working app (Angular2) and find that it is not working (Angular4) as expected now.
Module was used (it may not matter):
import { HttpModule, JsonpModule } from '#angular/http';
Module being used now:
import { HttpClientModule} from '#angular/common/http';
Trying to get a list of records from the backend (Node.js, Express, and MongoDB) as below.
listResource(resType: string, parameters: string[]) {
console.log("***listResource");
let headers = new HttpHeaders().set("X-CustomHeader", "custom header value");
headers.append('Content-Type', 'application/fhir+json');
headers.append("'Access-Control-Allow-Origin", "*");
headers.append("Accept", "application/fhir+json");
headers.append("USER_KEY", "QIF83Fjoe4sYxdQsah3h"); //TOUCHSTONE KEY
let urlString = this.baseUrl + resType + "/list"; // + queryString;
console.log("List resource URL string: [" + urlString + "]");
return (this.httpClient.get(urlString, { headers })
.map((res: Response) => res.json()))
.catch((error: any) => Observable.throw(error.json().error || 'Server error from Observable http.get call')); //...errors if any
}
when my component is loaded, the above listResource will be called as below.
ngOnInit() {
//Get the initial 25 latest patient
//this.progressBar = true;
this.currentPage = 0;
this.patientList = [];
this.globalSvc.gPatient = [];
console.log("***OnInit");
this.restSvc.listResource("Patient", ["identifier=*", "family=*", "given=*"]).subscribe(
data => {
console.log("Response data: " + JSON.stringify(data));
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
console.log('An error occurred:', err.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
}
});
}
Below is the output from Chrome console. Of course, I don't get any good response. It seems to me the Chrome browser sends CORS option and the server responds correctly, then the browser doesn't send the actual GET.
If I send the REST API request from PostMan directly which doesn't have CORS, I get the expected good response from the server. Hence, it seems to me the server is ok.
Questions:
Any idea how to debug or fix it?
Will this relate to CORS on both Angular client and Node.js server?
The ${err.status} and ${err.error} are "undefined" in Chrome console. How can I find the actual error?
console.log(Backend returned code ${err.status}, body was: ${err.error});
Update 1 based on Grey's suggestion on the immutable header and const.
The GET is returning data now.
headers.append() does not alter the headers, it returns a new Headers (because Headers is immutable).
So, instead of
let headers = new HttpHeaders().set("X-CustomHeader", "custom header value");
headers.append('Content-Type', 'application/fhir+json');
headers.append("'Access-Control-Allow-Origin", "*");
headers.append("Accept", "application/fhir+json");
headers.append("USER_KEY", "QIF83Fjoe4sYxdQsah3h"); //TOUCHSTONE KEY
you need to do something like:
let headers = new HttpHeaders().set("X-CustomHeader", "custom header value")
.append('Content-Type', 'application/fhir+json')
.append("'Access-Control-Allow-Origin", "*")
.append("Accept", "application/fhir+json")
.append("USER_KEY", "QIF83Fjoe4sYxdQsah3h");
Oh, and that should actually be const headers =, rather than let headers =

Resources