Angular HttpClient e Interceptors en 2026: Manejo de Peticiones y Preguntas de Entrevista

Guía completa sobre HttpClient e interceptors en Angular 2026. Arquitectura de peticiones HTTP, manejo de errores, autenticación y preguntas frecuentes en entrevistas técnicas.

Angular HttpClient e Interceptors

Angular continúa siendo en 2026 uno de los frameworks frontend más utilizados en entornos empresariales, y el dominio de HttpClient representa una habilidad esencial para cualquier desarrollador Angular. Esta guía explora en profundidad el funcionamiento de HttpClient, la arquitectura de los interceptors funcionales, y las preguntas más frecuentes en entrevistas técnicas.

Desde Angular 15, los interceptors funcionales reemplazan progresivamente a los interceptors basados en clases. Esta guía cubre ambos enfoques, con énfasis en los patrones modernos recomendados en 2026.

Configuración de HttpClient en Angular 19

La configuración de HttpClient ha evolucionado considerablemente con la adopción de standalone components. El método moderno utiliza provideHttpClient() en la configuración de la aplicación.

app.config.tstypescript
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
import { authInterceptor } from './interceptors/auth.interceptor';
import { errorInterceptor } from './interceptors/error.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withInterceptors([authInterceptor, errorInterceptor]),
      withFetch() // Uses fetch API instead of XMLHttpRequest
    )
  ]
};

La opción withFetch() permite utilizar la API Fetch nativa del navegador en lugar de XMLHttpRequest, ofreciendo mejor rendimiento y una integración más fluida con los Service Workers.

Creación de un Servicio HTTP Tipado

Un servicio HTTP bien estructurado constituye la base de una arquitectura Angular robusta. El uso de genéricos TypeScript garantiza la seguridad de tipos a través de toda la aplicación.

services/api.service.tstypescript
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../environments/environment';

export interface ApiResponse<T> {
  data: T;
  message: string;
  status: number;
}

export interface PaginatedResponse<T> {
  items: T[];
  total: number;
  page: number;
  pageSize: number;
}

@Injectable({ providedIn: 'root' })
export class ApiService {
  private http = inject(HttpClient);
  private baseUrl = environment.apiUrl;

  get<T>(endpoint: string, params?: Record<string, string>): Observable<ApiResponse<T>> {
    const httpParams = new HttpParams({ fromObject: params || {} });
    return this.http.get<ApiResponse<T>>(`${this.baseUrl}${endpoint}`, { params: httpParams });
  }

  post<T, R>(endpoint: string, body: T): Observable<ApiResponse<R>> {
    return this.http.post<ApiResponse<R>>(`${this.baseUrl}${endpoint}`, body);
  }

  put<T, R>(endpoint: string, body: T): Observable<ApiResponse<R>> {
    return this.http.put<ApiResponse<R>>(`${this.baseUrl}${endpoint}`, body);
  }

  delete<T>(endpoint: string): Observable<ApiResponse<T>> {
    return this.http.delete<ApiResponse<T>>(`${this.baseUrl}${endpoint}`);
  }

  uploadFile(endpoint: string, file: File): Observable<ApiResponse<{ url: string }>> {
    const formData = new FormData();
    formData.append('file', file);
    return this.http.post<ApiResponse<{ url: string }>>(`${this.baseUrl}${endpoint}`, formData);
  }
}

Interceptors Funcionales: El Enfoque Moderno

Los interceptors funcionales introducidos en Angular 15 ofrecen una sintaxis más concisa y mejor composabilidad. Se integran perfectamente con la arquitectura standalone.

Interceptor de Autenticación

La adición automática del token de autenticación representa el caso de uso más común de los interceptors.

interceptors/auth.interceptor.tstypescript
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const authService = inject(AuthService);
  const token = authService.getAccessToken();

  if (token && !req.url.includes('/auth/')) {
    const clonedRequest = req.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`
      }
    });
    return next(clonedRequest);
  }

  return next(req);
};

Interceptor de Manejo de Errores

Un interceptor centralizado para el manejo de errores simplifica considerablemente el código de los componentes.

interceptors/error.interceptor.tstypescript
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, throwError } from 'rxjs';
import { NotificationService } from '../services/notification.service';

export const errorInterceptor: HttpInterceptorFn = (req, next) => {
  const router = inject(Router);
  const notifications = inject(NotificationService);

  return next(req).pipe(
    catchError((error: HttpErrorResponse) => {
      switch (error.status) {
        case 401:
          router.navigate(['/login']);
          break;
        case 403:
          notifications.error('Access denied');
          break;
        case 404:
          notifications.error('Resource not found');
          break;
        case 500:
          notifications.error('Server error. Please try again later.');
          break;
        default:
          notifications.error(error.message || 'An error occurred');
      }
      return throwError(() => error);
    })
  );
};

Interceptor de Retry con Backoff Exponencial

El manejo de fallos de red transitorios requiere una estrategia de reintentos inteligente.

interceptors/retry.interceptor.tstypescript
import { HttpInterceptorFn } from '@angular/common/http';
import { retry, timer } from 'rxjs';

export const retryInterceptor: HttpInterceptorFn = (req, next) => {
  const maxRetries = 3;
  const delayMs = 1000;

  return next(req).pipe(
    retry({
      count: maxRetries,
      delay: (error, retryCount) => {
        if (error.status >= 400 && error.status < 500) {
          throw error; // Don't retry client errors
        }
        const backoffDelay = delayMs * Math.pow(2, retryCount - 1);
        console.log(`Retry attempt ${retryCount} after ${backoffDelay}ms`);
        return timer(backoffDelay);
      }
    })
  );
};

Gestión de Caché con Interceptors

La implementación de una caché HTTP a nivel de interceptor permite optimizar el rendimiento sin modificar los servicios existentes.

interceptors/cache.interceptor.tstypescript
import { HttpInterceptorFn, HttpResponse } from '@angular/common/http';
import { of, tap } from 'rxjs';

const cache = new Map<string, { response: HttpResponse<unknown>; timestamp: number }>();
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes

export const cacheInterceptor: HttpInterceptorFn = (req, next) => {
  if (req.method !== 'GET') {
    return next(req);
  }

  const cacheKey = req.urlWithParams;
  const cached = cache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
    return of(cached.response.clone());
  }

  return next(req).pipe(
    tap((event) => {
      if (event instanceof HttpResponse) {
        cache.set(cacheKey, { response: event.clone(), timestamp: Date.now() });
      }
    })
  );
};

Interceptor de Loading Global

La visualización automática de un indicador de carga mejora la experiencia del usuario.

interceptors/loading.interceptor.tstypescript
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { finalize } from 'rxjs';
import { LoadingService } from '../services/loading.service';

export const loadingInterceptor: HttpInterceptorFn = (req, next) => {
  const loadingService = inject(LoadingService);
  
  if (req.headers.has('X-Skip-Loading')) {
    return next(req);
  }

  loadingService.show();

  return next(req).pipe(
    finalize(() => loadingService.hide())
  );
};

Patrones Avanzados: Refresh Token Automático

La gestión automática del refresh token representa un patrón esencial para aplicaciones seguras.

interceptors/token-refresh.interceptor.tstypescript
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { BehaviorSubject, throwError } from 'rxjs';
import { catchError, filter, switchMap, take } from 'rxjs/operators';
import { AuthService } from '../services/auth.service';

let isRefreshing = false;
const refreshTokenSubject = new BehaviorSubject<string | null>(null);

export const tokenRefreshInterceptor: HttpInterceptorFn = (req, next) => {
  const authService = inject(AuthService);

  return next(req).pipe(
    catchError((error: HttpErrorResponse) => {
      if (error.status !== 401 || req.url.includes('/auth/refresh')) {
        return throwError(() => error);
      }

      if (isRefreshing) {
        return refreshTokenSubject.pipe(
          filter((token) => token !== null),
          take(1),
          switchMap((token) => {
            const cloned = req.clone({
              setHeaders: { Authorization: `Bearer ${token}` }
            });
            return next(cloned);
          })
        );
      }

      isRefreshing = true;
      refreshTokenSubject.next(null);

      return authService.refreshToken().pipe(
        switchMap((response) => {
          isRefreshing = false;
          refreshTokenSubject.next(response.accessToken);
          const cloned = req.clone({
            setHeaders: { Authorization: `Bearer ${response.accessToken}` }
          });
          return next(cloned);
        }),
        catchError((refreshError) => {
          isRefreshing = false;
          authService.logout();
          return throwError(() => refreshError);
        })
      );
    })
  );
};

¿Listo para aprobar tus entrevistas de Angular?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Preguntas Frecuentes en Entrevistas

Las siguientes preguntas aparecen regularmente durante las entrevistas técnicas de Angular.

¿Cuál es la diferencia entre HttpClient y la API Fetch nativa?

HttpClient ofrece varias ventajas sobre la API Fetch: integración nativa con RxJS, sistema de interceptors, tipado fuerte con TypeScript, y manejo automático de serialización JSON. La API Fetch es más ligera pero requiere más código boilerplate.

¿Cómo funciona el orden de ejecución de los interceptors?

Los interceptors se ejecutan en el orden de su declaración para las peticiones salientes, y en orden inverso para las respuestas entrantes. Esta arquitectura en "cebolla" permite encadenar las transformaciones de manera predecible.

¿Cómo cancelar una petición HTTP en curso?

La cancelación se realiza mediante la desuscripción al Observable retornado por HttpClient. El uso del operador takeUntil con un Subject permite gestionar correctamente la cancelación durante la destrucción de un componente.

typescript
// Example: Cancelling requests on component destroy
import { Component, OnDestroy } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';

@Component({ /* ... */ })
export class SearchComponent implements OnDestroy {
  private destroy$ = new Subject<void>();

  search(term: string) {
    this.apiService.search(term)
      .pipe(takeUntil(this.destroy$))
      .subscribe(results => this.results = results);
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

¿Cuándo usar HttpParams vs un objeto simple?

HttpParams garantiza la codificación correcta de los parámetros URL y soporta valores múltiples para una misma clave. Un objeto simple es adecuado para casos simples, pero HttpParams se recomienda para peticiones complejas.

¿Cómo probar un servicio que utiliza HttpClient?

Angular proporciona HttpTestingController para simular las peticiones HTTP en pruebas unitarias. Este enfoque permite verificar las URLs llamadas, los headers enviados, y simular diferentes respuestas.

typescript
// Example: Testing HTTP service
import { TestBed } from '@angular/core/testing';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';

describe('ApiService', () => {
  let service: ApiService;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        provideHttpClient(),
        provideHttpClientTesting()
      ]
    });
    service = TestBed.inject(ApiService);
    httpMock = TestBed.inject(HttpTestingController);
  });

  it('should fetch users', () => {
    const mockUsers = [{ id: 1, name: 'John' }];

    service.get<User[]>('/users').subscribe(response => {
      expect(response.data).toEqual(mockUsers);
    });

    const req = httpMock.expectOne('/api/users');
    expect(req.request.method).toBe('GET');
    req.flush({ data: mockUsers, message: 'OK', status: 200 });
  });

  afterEach(() => {
    httpMock.verify();
  });
});

Buenas Prácticas en 2026

Varias recomendaciones emergen para un uso óptimo de HttpClient en producción.

La centralización de las llamadas HTTP en servicios dedicados facilita el mantenimiento y las pruebas. El uso sistemático de interceptors para preocupaciones transversales (autenticación, logging, caché) evita la duplicación de código.

El tipado estricto de todas las respuestas API con interfaces TypeScript permite detectar errores en tiempo de compilación. La adopción de interceptors funcionales simplifica la configuración y mejora el rendimiento gracias al tree-shaking.

El manejo explícito de errores en cada nivel (interceptor global para errores comunes, manejo específico en componentes para casos particulares) garantiza una experiencia de usuario coherente.

Conclusión

HttpClient y los interceptors constituyen la base de la comunicación HTTP en aplicaciones Angular. El dominio de estos conceptos, desde los patrones básicos hasta técnicas avanzadas como el refresh token automático, representa una competencia clave evaluada en las entrevistas técnicas. La adopción de interceptors funcionales y las buenas prácticas presentadas en esta guía permite construir aplicaciones robustas y mantenibles.

Reto diario

¿Sabrías detectar el bug en Angular?

Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador de SharpSkill

Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.

Actualizado el 22 de agosto de 2026

Etiquetas

#angular
#httpclient
#interceptors
#http
#typescript

Compartir

Artículos relacionados