cannot retrieve data from angular http - mongodb

I'm trying to retrieve data from a collection in my mongodb using http module using the code below,
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts').map(res => {
console.log("mapped result",res);
res.json()
});
}
It fails everytime with a response
Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>)
at Response.webpackJsonp.../../../http/#angular/http.es5.js.Body.json (http.es5.js:797)
at MapSubscriber.project (auth.service.ts:45)
at MapSubscriber.webpackJsonp.../../../../rxjs/operators/map.js.MapSubscriber._next (map.js:79)
at MapSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at XMLHttpRequest.onLoad (http.es5.js:1226)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:425)
at Object.onInvokeTask (core.es5.js:3881)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask (zone.js:192)
but when I try it with postman, I'm getting the expected result which is this,
I'm returning the response from the service and subscribing its data from a component like this,
ngOnInit() {
this.auth.getPosts().subscribe(data => {
this.value = data.posts;
console.log("blog component",this.value)
},err => {
console.log(err);
})
}
What am I doing wrong? Any help would be much appreciated

You need to convert the response in map and subscribe to it to get the final JSON response
Updated code would look like this-
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts')
.map(res => res.json())
.subscribe((data: any) => {
//console.log(data);
});
}
I hope this helps. :)

Try returning inside the .map()
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts').map(res => {
console.log("mapped result",res);
return res.json()
});
}
}
or drop the brackets (this gives you an implied return),
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts')
.map(res => res.json() );
}
}

Related

Ionic Storage : Strange behavior?

I try to use the Ionic Storage module to store some values, for example my authentication token :
/**
* Get Token
*/
public get token(): string {
this.storage.get(this.LS_TOKEN).then((val) => {
console.log(val);
this._token.next(val);
console.log( this._token.getValue());
});
return this._token.getValue();
// return 'testtttt';
}
I try multiple things, return directly the value, set the value and return the variable...
But I always got a null, and the thing that is strange is that if I return a string directly it works, when I console.log the val it show the string that I want, but the return is always null..
What am I doing wrong ?
Edit :
In response of the first answer I have tried this :
/**
* Get Token
*/
public get token() {
this.tokenPromise().then(yourToken => {
console.log(yourToken);
return yourToken;
});
}
public tokenPromise() {
return new Promise((resolve, reject) => {
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex => {
reject(ex);
});
});
}
My problem is the same, in my components when I try to use : console.log(this.sharedService.token);
It's still null
It is not working with your new token() method.
It is still asnychron. Im gonna show you:
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
Now you can use your token from the sharedservice like this:
this.sharedService.token.then(token=>{
//use token here;
});
or you can use await, but the function who is calling it, must be async:
async useTokenFromService(){
let token = await this.sharedService.token;
console.log(token);
}
You are getting a Promise from the storage.get() method.
This means it is running asynchron.
You can return Promise.
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
And you can receive this with an async function and await the result:
async loadToken(){
let loadedToken = await this.token();
// use your loadedToken here...
}
Or you can use the .then method from the promise like this:
loadToken(){
this.token().then(yourToken=>{
// use the token yourToken here...
});
}

How to get axios error response INTO the redux saga catch method

With axios the code is:
export const createBlaBla = (payload) => {
return axios.post('/some-url', payload)
.then(response => response)
.catch(err => err);
}
And then I'm using this with redux-saga like this:
function* createBlaBlaFlow(action) {
try {
const response = yield call(createBlaBla, action.payload);
if (response) {
yield put({
type: CREATE_BLA_BLA_SUCCESS
});
}
} catch (err) {
// I need the error data here ..
yield put({
type: CREATE_BLA_BLA_FAILURE,
payload: 'failed to create bla-bla'
});
}
}
In case of some error on the backend - like invalid data send to the backend - it returns a 400 response with some data:
{
"code":"ERR-1000",
"message":"Validation failed because ..."
"method":"POST",
"errorDetails":"..."
}
But I don't receive this useful data in the catch statement inside the saga. I can console.log() the data in the axios catch statement, also I can get it inside the try statement in the saga, but it never arrives in the catch.
Probably I need to do something else? ... Or the server shouldn't return 400 response in this case?
So, I came up with two solutions of this problem.
===
First one - very dump workaround, but actually it can be handy in some specific cases.
In the saga, right before we call the function with the axios call inside, we have a variable for the errors and a callback that sets that variable:
let errorResponseData = {};
const errorCallback = (usefulErrorData) => {
errorResponseData = usefulErrorData;
};
Then - in the axios method we have this:
export const createBlaBla = (payload, errCallback) => {
return axios.post('/some-url', payload)
.then(response => response)
.catch(err => {
if (err && err.response.data && typeof errCallback === 'function') {
errCallback(err.response.data);
}
return err;
});
}
This way, when we make request and the backend returns errors - we'll call the callback and will provide the errors from the backend there. This way - in the saga - we have the errors in a variable and can use it as we want.
===
However, another solution came to me from another forum.
The problem I have is because in the method with the axios call I have catch, which means that the errors won't bubble in the generator. So - if we modify the method with the axios call like this:
export const createBlaBla = (payload) => {
return axios.post('/some-url', payload)
}
Then in the catch statement in the saga we'll have the actual backend error.
Hope this helps someone else :)
In your API call you can do the following:
const someAPICall = (action) => {
return axios.put(`some/path/to/api`, data, {
withCredentials: true,
validateStatus: (status) => {
return (status == 200 || status === 403);
}
});
};
Please note the validateStatus() part - this way when axios will encounter 200 or 403 response, it will not throw Error and you will be able to process the response after
const response = yield call(someAPICall, action);
if (response.status === 200) {
// Proceed further
} else if (response.status === 403) {
// Inform user about error
} else {
...
}

Return data in json after subscribe

I am using Angular 5 and want to return data from function getDionaeaResults in json format after subscribing to service
getDionaeaResults(sql) : any {
this.dionaeaService.getDionaeaConnectionLogs(sql).subscribe(res => {
this.data = res;
}),
(error: any) => {
console.log(error);
});
return this.data;
}
After calling this function, this.totalAttacks prints undefined.
getTotalAttack() {
this.totalAttacks = this.getDionaeaResults("some query")
console.log(this.totalAttacks,'attacks')
}
Would suggest using the Obseravable .map() function.
getDionaeaResults(sql) : Observable<any> {
return this.dionaeaService
.getDionaeaConnectionLogs(sql)
.map(res => res);
}
getTotalAttack(sql){
this.getDionaeaResults("some query")
.subscribe(
res => { this.totalAttacks = res; },
err => { console.log(err); }
);
}
this.getDionaeaResults is returning undefined because the service you're calling is asynchronous you have to wait for the subscribe callback. as Observables are asynchronous calls
this.data=res
might execute after the return statement. You can perhaps call that dionaeaService directly inside getTotalAttack() function, like this:
getTotalAttack(sql){
this.dionaeaService.getDionaeaConnectionLogs(sql).subscribe(res => {
this.totalAttacks = res;
}),
(error: any) => {
console.log(error);
});
}

api request returns undefined

maybe is a stupid question but,
when I'm calling api from 'outside' function it always returns undefined,
for example:
actions.js
import axios from 'axios'
export function getProducts() {
axios.get('http://localhost:8000/api/products').then((response) => {
return response;
});
}
and then in a component:
mounted() {
this.products = getProducts();
console.log(this.products);
}
returns undefined
of course when I make a request from component it returns result
mounted() {
axios.get('http://localhost:8000/api/products').then((response) => {
this.products = response;
console.log(this.products);
});
}
Why is this happening and how can I solve this problem?
Thanks
You are returning the response value in the then callback of the axios.get call. However, your getProducts function doesn't return anything.
Simply return the axios.get call:
export function getProducts() {
return axios.get('http://localhost:8000/api/products');
}
Then, the result of getProducts will be the Promise returned by axios.get(). So, you can add a then callback on the result of getProducts and set you this.products that way:
mounted() {
getProducts().then(products => this.products = products);
}

Observable switch/flatMap fires instantly

I have the following code in my service:
public loginWithFacebook(): Observable<any> {
console.log('Login');
return Observable.fromPromise(this.fb.login()).flatMap((userData) => {
return this.http.post(authFacebook, {access_token: userData.authResponse.accessToken}, { observe: 'response' });
}).do( (response: HttpResponse<any>) => {
const token = response.headers.get('x-auth-token');
if (token) {
localStorage.setItem('id_token', token);
}
});
}
getFacebookProfile():Observable<any> {
console.log("Get Profile");
return Observable.fromPromise(this.fb.getLoginStatus())
.filter((state) => state.status === 'connected')
.switchMapTo(Observable.fromPromise(this.fb.api('/me')));
}
And later I use it in my component to get the profile info once login is successful.
this.profileData = this.usersService.loginWithFacebook()
.flatMapTo(this.usersService.getFacebookProfile());
However, for some reason getFacebookProfile() fires instantly even before the login procedure is complete. And I get an authentication error. Also, I have to login twice to get profile info displayed.
I've been always thinking that switchMap and flatMap only switch to the next observable once the previous one emits a value.
What am I doing wrong here?
--EDIT--
If I subscribe to the first Observable and call getFacebookProfile() in the subscription, everything works normally. But it's not very elegant solution I feel.
The problem is that promises are eager. You are calling this.fb.login() when you compose your observable and you are passing the returned promise into fromPromise.
That means that the login is initiated when loginWithFacebook is called and not when subscribe is called on the observable it returns.
If you want the login to be deferred until subscribe is called, you can use defer:
public loginWithFacebook(): Observable<any> {
console.log('Login');
return Observable.defer(() => Observable.fromPromise(this.fb.login()))
.flatMap((userData) => {
return this.http.post(authFacebook, {
access_token: userData.authResponse.accessToken
}, { observe: 'response' });
})
.do( (response: HttpResponse<any>) => {
const token = response.headers.get('x-auth-token');
if (token) {
localStorage.setItem('id_token', token);
}
});
}
For more information on using observables and promises, see Ben Lesh's article: RxJS Observable interop with Promises and Async-Await
It worked at last thanks to #cartant's answer. However, for some reason, I had to wrap it with defer operator twice. I would be thankful if someone could explain why it was necessary to do it. It's a bit weird.
public loginWithFacebook(): Observable<any> {
return Observable.defer(() =>
Observable.defer(() => this.fb.login()).flatMap((userData) =>
{
return this.http.post(authFacebook, {access_token: userData.authResponse.accessToken}, { observe: 'response' });
}).do( (response: HttpResponse<any>) => {
const token = response.headers.get('x-auth-token');
if (token) {
localStorage.setItem('id_token', token);
}
})
);
}
getFacebookProfile():Observable<any> {
return Observable.defer(() =>
Observable.defer(() => this.fb.getLoginStatus())
.filter((state) => state.status === 'connected')
.switchMapTo(Observable.fromPromise(this.fb.api('/me')))
);
}