I have a confusion about switchMap in rxjs Observable:
for example i have next code:
Observable.fromEvent(button, 'click')
.switchMap(() => Observable.fromPromise(fetch('http://return-error.com')))
.subscribe(
(response) => {
console.log(response);
},
(error) => {
console.log(error);
}
);
If I get error from fetch, subscription is interrupted. So is there way to handle it to not create new subscription for any error?
I have even tried to catch error and return Observable, but subscription is interrupted anyway.
upd: how to deal with angular 2 http.get instead of fetch?
It's always more helpful if you make a Bin when asking these questions. I did it for you on this one.
You simply need to swallow the error in the fetch call. E.g.
fetch('bad-url').catch(err => 'Error but keep going')
Here's the demo. Click the document (output) to fire the event.
http://jsbin.com/vavugakere/edit?js,console,output
(You'll need a browser with native Fetch implementation or it'll throw an error)
Related
I have started to use the lastValueFrom() to handle my observable http requests. One of these http calls is returning an error from the server-side, and I am getting the name: 'EmptyError', message: 'no elements in sequence' message
const response = await lastValueFrom(
this.service.doStuff()
).catch((e) => {
console.log('#1', e);
return {} as DoStuffResponse;
});
at #1 the error is EmptyError , not the error from the http call.
I understand why I am getting it (the http observable does not return a value)
However, what I'd like to know is what the actual error is (a 422 unprocessable entity in this case)
Is this possible ?
I have not found a method to catch the Http errors from lastValueFrom and this does not appear to be documented in rxjs.
As a result I've decided to avoid lastValueFrom when doing Http requests. Instead I stick with Subscribe and always get the Http response codes in the error.
As an aside, many people noticed Subscribe as being deprecated in VSCode, but this is not true; just a certain overload. I know you didn't mention the deprecation as a motivator for using lastValueFrom, but I think most people, including myself, used the VSCode deprecation alert as a prompt to switch.
That said, this Subscribe syntax is still valid and should give you the Http error code:
this.someService.getResults.subscribe(
{
next: (results) => {
console.log('Here are the results...', results);
},
error: (err: any) => {
console.log('Here is the error...', err.status);
},
complete: () => { }
});
I've got an Api call that is converted to a promise. My handleError function inside the observable re-throws via throwError. This re-thrown error does not trigger any catch in the outer Promise chain.
callApi() {
return this.http.get(`${this.baseUrl}/someapi`)
.pipe(
map((data: any) => this.extractData(data)),
catchError(error => this.handleError(error))
).toPromise();
handleError(error) {
console.error(error);
return throwError(error || 'Server error');
}
Calling code...
this.someService.callApi()
.then((response) => {
// THIS GETS CALLED AFTER throwError
// do something cool with response
this.someVar = response;
})
.catch((error) => {
// WE NEVER GET TO HERE, even when I force my api to throw an error
console.log(`Custom error message here. error = ${error.message}`);
this.displayErrorGettingToken();
});
Why doesn't the throwError trigger the Promise catch?
You should not use toPromise() when possible.
Use subscribe instead of then.
Also when you catch the error in a pipe it won't be thrown in then because you already caught it, also when you throw the error in a catch error, it won't be emitted into the regular pipe flow of your response.
callApi() {
return this.http.get(`${this.baseUrl}/someapi`);
}
This is totally ok. Http.get() returns a singleton observable stream, which emits only ONE value and then completes. Subscribe to the Observable.
this.someService.callApi()
.subscribe((response) => {
// THIS GETS CALLED always wenn everything is ok
this.someVar = response;
},
(error:HttpErrorResponse) =>{
console.log(`Custom error message here. error ${error.message}`);
this.displayErrorGettingToken();
});
Observable is like an extended version of promise. Use it.
mergeMap( (action)=>{
const data = action.data;
console.log(state$.value,'\n',action.data);
Calling API here. How to handle the network error returned by this call?
from(axios.post('http://localhost:3000/addContactIntoDirectory',
{directoryId: state$.value.reducer1.SelectedDirectory, contact: data.contact})
))
basically, in RXJS catch and catchError is identical. You can refer the documentation RxJs catch/catchError for more info. Docs also states that we have to return observable from catchError.
have a look at the given example related to your library axios context,
axios.post('/formulas/create', { name: "Atul", parts: "Mishra" })
.then(response => {
console.log(response)
}).catch(error => {
console.log(error.response)
});
I have an rxjs.observable (rxjs version 6.2.1) that returns urls I need to make a GET request to.
var subscription = urlObservable$.subscribe(
function (url) {
console.log('new URL: ' + url);
processURL(url)
},
function (err) { console.log('Error: ' + err); },
function () { console.log('Completed'); }
);
For every url I need to make the request via the function processURL(url). What is the correct way, accordingly to the react philosophy, to process all this incoming urls and make the requests one by one instead of firing all of them as soon as the subscribe emits data? Please note that in this case, the observable urlObservable$ will return data much faster than the request that needs to be made with the returned url.
processURL can return a promise.
Thanks.
If urlObservable$ is emitting just strings you can simply use concatMap that always waits until the previous Observable completes:
urlObservable$
.pipe(
concatMap(url => processURL(url)),
)
.subscribe(...);
This will work even if processURL returns a Promise.
A "authenticationService" provides the following authenticate method. I'm unable to enter the piped catchError. What am I missing?
authenticate(credentials: { username: string; password: string }){
return new Observable<any>((observer: Observer<any>) => {
// ... calling the service, obtaining a promise
const authenticationPromise = ... ;
// This is a promise, it must be converted to an Observable
authenticationPromise
.then(() => {
observer.next('ok');
observer.complete();
})
.catch(err => {
console.log('service error ' + err);
throw new Error('crap');
});
});
}
Setting all the ngrx & ngrx/effect part aside, this authentication method is called upon user request:
(redux stuff).(({ payload }: actions.LoginRequestAction) =>
context.authService.authenticate(payload)
.pipe(
map(() => new GenericSuccessAction(...))
// Even though a throw statement happened in the authenticate method, this is never reached:
catchError((err: Error) => {
console.log('[debug] error caught: ', err);
return of(new actions.LoginFailureAction());
}),
)
)
As stated here, catchError is used to:
Gracefully handle errors in an observable sequence.
First of all, you are basically handling the error in your promise by catching the error in your promise. Throwing the error in the promise doesn't return an observable that emits an error.
You can:
Convert your promise into an observable and don't use .catch at all.
Return the error as an observable with rxjs' throwError(err)
Either way, the way you create your observable is questionable.
This is a much better and concise way to handle promises in rxjs:
from(authenticationPromise)
.pipe(
map(() => 'ok')
)