I'm facing problem when catching the error from the API. As you can see below, I'm calling deletedJob method when clicks on delete button and that function call 'deleteJob' function of jobService.
In Component
deleteJob(id) {
this.jobService.deleteJob(id, this.shopId)
.then(res => {
console.log('response');
// Displaying the success message
})
.catch(this.handleError)
}
});
}
deletedJob function in jobService component
deleteJob(id: number, shopId: number) {
let url = this.jobsUrl() + `/${id}.json`;
return this.http
.delete(url)
.toPromise()
.then(res => res.json().response)
.catch(this.handleError);
}
handleError function for above function
handleError(error: any) {
return Promise.reject(error.message || error);
}
So when rejecting that error through handleError function, I'm getting an error in console 'TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.'
Related
component which is calling submitUser
this.someservice.submitUser(postData).subscribe((data) => {
this.viewUsers();
}, (err) => {
console.log('error in the component', err);
});
Here is the service file with submitUser function
public submitUser(reqBody ) {
return this.httpService.post('roles', reqBody, '/business/create')
.pipe(
catchError(
this.httpService.handleError())
);
}
and here is the httpService Post and handleError methods
public post<JSON>(url: string, body: any, param?: string, options?: IRequestOptions): Observable<JSON> {
return this.intercept(this.http.post<JSON>(this.getURLFromMethodName(url, param), body, this.requestOptions(options)));
}
handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error('error from httpclient', error); // log to console instead
throw throwError(new Error(error));
};
}
handleError adisplays the console error, I am trying to return/capture this error in my submitUser function in service.ts
How do i do that ? Any Inputs appreciated, Thanks
Your handleError() method returns an error observable along with logging the error to the console.
When some error occurs, the catchError operator takes that error and gives it to handleError() which in turn returns an error observable.
CASE 1: Returning the error
If you need to pass this error on to the subscriber, you don't have to do anything. The catchError operator is already taking care of it for you.
With the same code, let's say some component is consuming your service, then you can just write
someService.submitUser().subscribe((res) => {
\\ handle success
}, (err) => {
console.error(err); // Will print the error
});
Whenever the error occurs, the catchError is going to return the error observable back to its subscriber and it will go in the error function of the observer as shown in the code snippet above.
CASE 2: Handling the error
The catchError operator accepts a function that takes error as an argument. If you return another observable inside this instead of throwing an error, the subscriber won't get to know that the error had occurred, the success function of the observer will execute.
// Inside the service
public submitUser(reqBody ) {
return this.httpService.post('roles', reqBody, '/business/create')
.pipe(
catchError((err) => of([1,2,3]));
}
// Inside the component consuming the service
someService.submitUser().subscribe((res) => {
console.log(res) // Will print [1,2,3]
}, (err) => {
\\ handle error
});
I am using the below methods to send data. I want to display an error response on my component. How can I console log error message in my component?
component.ts
signup(){
return this.loginservice.signupUser(this.model).subscribe(data => {
console.log(data.error);
});
}
service ts
signupUser(signupuserModel: any = {}):Observable<any>{
return this.http.post(`${this.signuouserurl}`,signupuserModel)
}
error message
In RxJS, subscribe() method can have 3 functions
next() if observable emits value.
error() if there's an error thrown from the Observable
complete() if the observable is completed.
What you need to do is to add an extra arrow function in your server call inside subscribe() method
public error: any;
signup() {
return this.loginservice.signupUser(this.model).subscribe(success => {
console.log(success);
}, error => { // second parameter is to listen for error
console.log(error);
this.error = error;
});
}
If you want to show the error in your component.html, you can use the interpolation {{ }}
component.html
<div class="error">{{ error }}</div>
try
signup() {
return this.loginservice.signupUser(this.model).subscribe(data => {
console.log(data);
}, err => {
console.log(err);
});
}
You can also use try-catch approach in following way
async signup() {
try {
let data = await this.loginservice.signupUser(this.model).toPromise();
console.log(data)
} catch (e) {
console.log(e);
}
}
However not all http codes raise exception
you can choose any method to display an error.. on of the best way is seprate the success and error response with following code (for this your http call must thrown an exception if not then you have to chose the second option )
signup() {
return this.loginservice.signupUser(this.model).subscribe(success => {
console.log(success);
}, error => {
console.log(error);
});
}
or you can write conditional code like
signup() {
return this.loginservice.signupUser(this.model).subscribe(success => {
console.log(data);
if(success.status == 406){ console.log("success")}
else { console.log("Error ") }
}
}
I am doing a simple fetch using Typescript in a Class, which should return a promise, then I want to get the JSON response from this fetch. However, no matter what change I make, the function is always returning a Promise<void | T> which is ruining the type checking in my code.
export class ApiHelper {
constructor() { }
public FetchFromPortal<T>(xyz: string) {
------ Other less relevant code -----------
return fetch(url, options)
.then((response) => this.CheckStatus(response))
.then((response) => this.ParseJSON<T>(response))
.then((response) => {
console.log(response);
return response;
})
.catch((error: Error) => { console.log(error) });
}
private CheckStatus(response : Response) : Promise<Response> {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response);
} else {
let error = new Error(response.statusText);
throw error;
}
}
private ParseJSON<T>(response : Response) {
return response.json() as Promise<T>;
}
}
I'm then subsequently calling it like this:
let result = apiHelper.FetchFromPortal<T>(xyz);
According to Typescript, this is returning a Promise<void | T>. I've tried resolving the promise in the call like so:
let result = apiHelper.FetchFromPortal<T>(xyz).then(data => { return data });
Which should in theory resolve the Promise but this doesn't appear to be working.
Any reason why the promise isn't resolving to just the object?
Any reason why the promise isn't resolving to just the object?
Here is the reason:
})
.catch((error: Error) => { console.log(error) });
When exception happens, this handler logs error to console and does not return anything. The compiler sees this and adds void union member to the return type.
Any reason why the promise isn't resolving to just the object?
Yes, promise resolution happens on some kind of "asynchronous space", the call will always just return a promise. The result of the promise is just forwarded through the then() chain and never returned to the caller (because they are asynchronous).
But I think you can have the behavior you are expecting by using await:
let result = await apiHelper.FetchFromPortal<T>(xyz);
I'm writing a REST API and trying to correctly handle any errors.
When the API call succeeds, the the success object is returned to the calling function and the response is send to the client. But if an error occurs, I want to return the error to the calling function so I can send an error message to the client.
router.delete('/project', (req, res) => {
return DeleteProject(userId, projectId)
.then((response) => {
//handle response
});
});
DeleteProject: (userId, projectId) => {
return deleteProject(userId, projectId)
.then((response) => {
return response
})
.catch((error) => {
console.log('Error in DeleteProject:', error) // This happens.
return error; // this doesn't happen.
})
},
function deleteProject(userId, projectId) {
return Project.deleteOne( ... delete the project... )
.then((response) => {
return response
})
.catch((error) => {
return error
})
}
The .catch(error) in the middle function above, DeleteProject(), gets triggered when an error occurs (ie, the console log happens), but the return doesn't make it's way back to the router.
How can I return the error to be handled by the router?
You can simply remove catch methods from the other two functions, and put the catch function in the router itself. Then the error will itself propagate to your router function
router.delete('/project', (req, res) => {
return DeleteProject(userId, projectId)
.then((response) => {
//handle response
}).catch(() => {
// Add catch function here. Any error in "DeleteProject" and "deleteProject" will propagate to here
})
});
DeleteProject: (userId, projectId) => {
return deleteProject(userId, projectId)
.then((response) => {
return response
});
// Remove catch function
},
function deleteProject(userId, projectId) {
return Project.deleteOne( ... delete the project... )
.then((response) => {
return response
});
// Remove catch function
}
To propagate errors through promise chains you need to throw them. In your catch handler, when you return the error rather than throwing it, you'e setting the (successfully) resolved value of the promise to be the error.
I have a provider that reads the data from a JSON and I want it to send the data to a page.
To ensure that the data is well sent to the UI I have a console.log that is supposed to show the first element of the array, but the issue is that I don't know how to only call this console.log once the information has been retrieved and passed by the provider.
the intention of course is not the console.log, but to do actual things with the data, once it's passed by the provider.
The provider :
getWorldCities(){
if (this.worldCities) {
// already loaded data
return Promise.resolve(this.worldCities);
}
this.http.get('../assets/city.list.json')
.map(res => res.json()).subscribe(data => {
console.log(data.status);
console.log(data);
console.log(data.headers);
this.worldCities = data;
return Promise.resolve(this.worldCities);
},
err => console.log(err),
() => console.log('yay')
)
}
}
And in my page :
ionViewDidLoad() {
console.log('ionViewDidLoad ChooseCity');
console.log(this.worldCities);
this.AppCitiesProvider.getWorldCities().then(data => {
this.worldCities = data;
console.log(this.worldCities[0]);
});
}
the error I get is :
Cannot read property 'then' of undefined
How should I do that properly ?
The "best practice" for retrieving data and performing operations once the data is received is to use the Observable instead of a promise. Something like this:
In the service:
getMovies(): Observable<IMovie[]> {
return this.http.get<IMovie[]>(this.moviesUrl)
.do(data => console.log(JSON.stringify(data)))
.catch(this.handleError);
}
handleError(error) {
// Your error handling here.
console.error(error);
}
In the component:
ngOnInit(): void {
this.movieService.getMovies()
.subscribe(
(movies: IMovie[]) => {
this.movies = movies;
this.filteredMovies = this.performFilter(this.listFilter);
},
(error: any) => this.errorMessage = <any>error);
}
Any code within the first callback function to the subscribe will only be executed after the data is retrieved.
See this for more information (and pictures!) Subscribe to observable is returning undefined