Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
get(url, params): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'get', null, params)
.map((res) => {
return res as Object
.toPromise();
post(url, body): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'post', body)
.map((res) => {
return res as Object
.toPromise();
patch(url, body): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'patch', body)
.map((res) => {
return res as Object
.toPromise();
sendRequest(url, type, body, params = null): Observable<any> {
return this.httpClient[type](url, { params: params }, body)
If I get an HTTP error (i.e. 404), I get a nasty console message:
ERROR Error: Uncaught (in promise): [object Object]
from
core.es5.js
How do I handle it in my case?
You have some options, depending on your needs. If you want to handle errors on a per-request basis, add a
catch
to your request. If you want to add a global solution, use
HttpInterceptor
.
Open
here the working demo plunker
for the solutions below.
tl;dr
In the simplest case, you'll just need to add a
.catch()
or a
.subscribe()
, like:
import 'rxjs/add/operator/catch'; // don't forget this, or you'll get a runtime error
this.httpClient
.get("data-url")
.catch((err: HttpErrorResponse) => {
// simple logging, but you can do a lot more, see below
console.error('An error occurred:', err.error);
// or
this.httpClient
.get("data-url")
.subscribe(
data => console.log('success', data),
error => console.log('oops', error)
But there are more details to this, see below.
Method (local) solution: log error and return fallback response
If you need to handle errors in only one place, you can use catch
and return a default value (or empty response) instead of failing completely. You also don't need the .map
just to cast, you can use a generic function. Source: Angular.io - Getting Error Details.
So, a generic .get()
method, would be like:
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from "@angular/common/http";
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/retry'; // don't forget the imports
@Injectable()
export class DataService {
baseUrl = 'http://localhost';
constructor(private httpClient: HttpClient) { }
// notice the <T>, making the method generic
get<T>(url, params): Observable<T> {
return this.httpClient
.get<T>(this.baseUrl + url, {params})
.retry(3) // optionally add the retry
.catch((err: HttpErrorResponse) => {
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
console.error('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.error(`Backend returned code ${err.status}, body was: ${err.error}`);
// ...optionally return a default fallback value so app can continue (pick one)
// which could be a default value
// return Observable.of<any>({my: "default value..."});
// or simply an empty observable
return Observable.empty<T>();
Handling the error will allow you app to continue even when the service at the URL is in bad condition.
This per-request solution is good mostly when you want to return a specific default response to each method. But if you only care about error displaying (or have a global default response), the better solution is to use an interceptor, as described below.
Run the working demo plunker here.
Advanced usage: Intercepting all requests or responses
Once again, Angular.io guide shows:
A major feature of @angular/common/http
is interception, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it before sending it to the server, and the interceptors can transform the response on its way back before your application sees it. This is useful for everything from authentication to logging.
Which, of course, can be used to handle errors in a very simple way (demo plunker here):
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse,
HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/retry'; // don't forget the imports
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.catch((err: HttpErrorResponse) => {
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
console.error('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.error(`Backend returned code ${err.status}, body was: ${err.error}`);
// ...optionally return a default fallback value so app can continue (pick one)
// which could be a default value (which has to be a HttpResponse here)
// return Observable.of(new HttpResponse({body: [{name: "Default value..."}]}));
// or simply an empty observable
return Observable.empty<HttpEvent<any>>();
Providing your interceptor: Simply declaring the HttpErrorInterceptor
above doesn't cause your app to use it. You need to wire it up in your app module by providing it as an interceptor, as follows:
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from './path/http-error.interceptor';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true,
export class AppModule {}
Note: If you have both an error interceptor and some local error handling, naturally, it is likely that no local error handling will ever be triggered, since the error will always be handled by the interceptor before it reaches the local error handling.
Run the working demo plunker here.
–
–
–
–
Let me please update the acdcjunior's answer about using HttpInterceptor with the latest RxJs features(v.6).
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpErrorResponse,
HttpHandler,
HttpEvent,
HttpResponse
} from '@angular/common/http';
import { Observable, EMPTY, throwError, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(`Backend returned code ${error.status}, body was: ${error.error}`);
// If you want to return a new response:
//return of(new HttpResponse({body: [{name: "Default value..."}]}));
// If you want to return the error on the upper level:
//return throwError(error);
// or just return nothing:
return EMPTY;
–
–
With the arrival of the HTTPClient
API, not only was the Http
API replaced, but a new one was added, the HttpInterceptor
API.
AFAIK one of its goals is to add default behavior to all the HTTP outgoing requests and incoming responses.
So assumming that you want to add a default error handling behavior, adding .catch()
to all of your possible http.get/post/etc methods is ridiculously hard to maintain.
This could be done in the following way as example using a HttpInterceptor
:
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { _throw } from 'rxjs/observable/throw';
import 'rxjs/add/operator/catch';
* Intercepts the HTTP responses, and in case that an error/exception is thrown, handles it
* and extract the relevant information of it.
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
* Intercepts an outgoing HTTP request, executes it and handles any error that could be triggered in execution.
* @see HttpInterceptor
* @param req the outgoing HTTP request
* @param next a HTTP request handler
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req)
.catch(errorResponse => {
let errMsg: string;
if (errorResponse instanceof HttpErrorResponse) {
const err = errorResponse.message || JSON.stringify(errorResponse.error);
errMsg = `${errorResponse.status} - ${errorResponse.statusText || ''} Details: ${err}`;
} else {
errMsg = errorResponse.message ? errorResponse.message : errorResponse.toString();
return _throw(errMsg);
* Provider POJO for the interceptor
export const ErrorInterceptorProvider = {
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true,
// app.module.ts
import { ErrorInterceptorProvider } from 'somewhere/in/your/src/folder';
@NgModule({
providers: [
ErrorInterceptorProvider,
export class AppModule {}
Some extra info for OP: Calling http.get/post/etc without a strong type isn't an optimal use of the API. Your service should look like this:
// These interfaces could be somewhere else in your src folder, not necessarily in your service file
export interface FooPost {
// Define the form of the object in JSON format that your
// expect from the backend on post
export interface FooPatch {
// Define the form of the object in JSON format that your
// expect from the backend on patch
export interface FooGet {
// Define the form of the object in JSON format that your
// expect from the backend on get
@Injectable()
export class DataService {
baseUrl = 'http://localhost'
constructor(
private http: HttpClient) {
get(url, params): Observable<FooGet> {
return this.http.get<FooGet>(this.baseUrl + url, params);
post(url, body): Observable<FooPost> {
return this.http.post<FooPost>(this.baseUrl + url, body);
patch(url, body): Observable<FooPatch> {
return this.http.patch<FooPatch>(this.baseUrl + url, body);
Returning Promises
from your service methods instead of Observables
is another bad decision.
And an extra piece of advice: if you are using TYPEscript, then start using the type part of it. You lose one of the biggest advantages of the language: to know the type of the value that you are dealing with.
If you want a, in my opinion, good example of an angular service, take a look at the following gist.
For Angular 6+ , .catch doesn't work directly with Observable. You have to use
.pipe(catchError(this.errorHandler))
Below code:
import { IEmployee } from './interfaces/employee';
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
export class EmployeeService {
private url = '/assets/data/employee.json';
constructor(private http: HttpClient) { }
getEmployees(): Observable<IEmployee[]> {
return this.http.get<IEmployee[]>(this.url)
.pipe(catchError(this.errorHandler)); // catch error
/** Error Handling method */
errorHandler(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
// return an observable with a user-facing error message
return throwError(
'Something bad happened; please try again later.');
For more details, refer to the Angular Guide for Http
–
–
Fairly straightforward (in compared to how it was done with the previous API).
Source from (copy and pasted) the Angular official guide
.get<ItemsResponse>('/api/items')
.subscribe(
// Successful responses call the first callback.
data => {...},
// Errors will call this callback instead:
err => {
console.log('Something went wrong!');
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Student } from '../model/student';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
export class ApiService {
// API path
base_path = 'http://localhost:3000/students';
constructor(private http: HttpClient) { }
// Http Options
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
// Handle API errors
handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
// return an observable with a user-facing error message
return throwError(
'Something bad happened; please try again later.');
// Create a new item
createItem(item): Observable<Student> {
return this.http
.post<Student>(this.base_path, JSON.stringify(item), this.httpOptions)
.pipe(
retry(2),
catchError(this.handleError)
........
........
–
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
const PASSENGER_API = 'api/passengers';
getPassengers(): Observable<Passenger[]> {
return this.http
.get<Passenger[]>(PASSENGER_API)
.pipe(catchError((error: HttpErrorResponse) => throwError(error)));
–
get(url, params): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'get', null, params)
.map((res) => {
return res as Object
}).catch((e) => {
return Observable.of(e);
.toPromise();
caller:
this.dataService.get(baseUrl, params)
.then((object) => {
if(object['name'] === 'HttpErrorResponse') {
this.error = true;
//or any handle
} else {
this.myObj = object as MyClass
If you find yourself unable to catch errors with any of the solutions provided here, it may be that the server isn't handling CORS requests.
In that event, Javascript, much less Angular, can access the error information.
Look for warnings in your console that include CORB
or Cross-Origin Read Blocking
.
Also, the syntax has changed for handling errors (as described in every other answer). You now use pipe-able operators, like so:
this.service.requestsMyInfo(payload).pipe(
catcheError(err => {
// handle the error here.
@Injectable()
export class ResponseInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//Get Auth Token from Service which we want to pass thr service call
const authToken: any = `Bearer ${sessionStorage.getItem('jwtToken')}`
// Clone the service request and alter original headers with auth token.
const authReq = req.clone({
headers: req.headers.set('Content-Type', 'application/json').set('Authorization', authToken)
const authReq = req.clone({ setHeaders: { 'Authorization': authToken, 'Content-Type': 'application/json'} });
// Send cloned request with header to the next handler.
return next.handle(authReq).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log("Service Response thr Interceptor");
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
console.log("err.status", err);
if (err.status === 401 || err.status === 403) {
location.href = '/login';
console.log("Unauthorized Request - In case of Auth Token Expired");
You can prefer this blog..given simple example for it.
The worse thing is not having a decent stack trace which you simply cannot generate using an HttpInterceptor
(hope to stand corrected). All you get is a load of zone and rxjs useless bloat, and not the line or class that generated the error.
To do this you will need to generate a stack in an extended HttpClient
, so its not advisable to do this in a production environment.
* Extended HttpClient that generates a stack trace on error when not in a production build.
@Injectable()
export class TraceHttpClient extends HttpClient {
constructor(handler: HttpHandler) {
super(handler);
request(...args: [any]): Observable<any> {
const stack = environment.production ? null : Error().stack;
return super.request(...args).pipe(
catchError((err) => {
// tslint:disable-next-line:no-console
if (stack) console.error('HTTP Client error stack\n', stack);
return throwError(err);
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.