Módulo HTTP axios

Intermedio
Nest
Nest
Actualizado: 05/05/2026

Diagrama: tutorial-nest-httpmodule-axios

Módulo HTTP axios en Nest

El módulo HTTP de NestJS proporciona una integración nativa con axios para realizar peticiones HTTP a servicios externos. Este módulo encapsula la funcionalidad de axios dentro del ecosistema de NestJS, permitiendo aprovechar las ventajas de la inyección de dependencias y la gestión de configuración del framework.

Instalación y configuración básica

Para utilizar el módulo HTTP, primero debemos instalarlo junto con axios:

npm install @nestjs/axios axios

Una vez instalado, necesitamos importar el HttpModule en nuestro módulo. La configuración más básica se realiza de la siguiente manera:

import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { ApiService } from './api.service';

@Module({
  imports: [HttpModule],
  providers: [ApiService],
  exports: [ApiService],
})
export class ApiModule {}

Inyección del HttpService

El HttpService es el servicio principal que nos permite realizar peticiones HTTP. Se inyecta como cualquier otro servicio en NestJS:

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Observable } from 'rxjs';
import { AxiosResponse } from 'axios';

@Injectable()
export class ApiService {
  constructor(private readonly httpService: HttpService) {}

  getData(): Observable<AxiosResponse<any>> {
    return this.httpService.get('https://jsonplaceholder.typicode.com/posts');
  }
}

Es importante notar que el HttpService devuelve observables de RxJS, no promesas directamente. Esto permite un manejo más avanzado de las respuestas asíncronas.

Configuración avanzada del módulo

El HttpModule permite configuraciones más específicas mediante el método register():

import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';

@Module({
  imports: [
    HttpModule.register({
      timeout: 5000,
      maxRedirects: 5,
      baseURL: 'https://api.ejemplo.com',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token-ejemplo',
      },
    }),
  ],
  providers: [ApiService],
})
export class ApiModule {}

Esta configuración establece un timeout global, una URL base y headers por defecto que se aplicarán a todas las peticiones realizadas desde este módulo.

Manejo de respuestas con operadores RxJS

Dado que el HttpService devuelve observables, podemos utilizar operadores de RxJS para transformar y manejar las respuestas:

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { map, catchError } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';

@Injectable()
export class ApiService {
  constructor(private readonly httpService: HttpService) {}

  getUsers(): Observable<any[]> {
    return this.httpService
      .get('https://jsonplaceholder.typicode.com/users')
      .pipe(
        map(response => response.data),
        catchError(error => {
          console.error('Error al obtener usuarios:', error);
          return throwError(() => new Error('Error en la petición'));
        }),
      );
  }
}

El operador map() nos permite extraer únicamente los datos de la respuesta, mientras que catchError() maneja los errores de forma elegante.

Conversión a promesas

Si preferimos trabajar con promesas en lugar de observables, podemos convertir fácilmente las respuestas:

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class ApiService {
  constructor(private readonly httpService: HttpService) {}

  async getUserById(id: number): Promise<any> {
    try {
      const response = await firstValueFrom(
        this.httpService.get(`https://jsonplaceholder.typicode.com/users/${id}`)
      );
      return response.data;
    } catch (error) {
      throw new Error(`Error al obtener usuario ${id}: ${error.message}`);
    }
  }
}

La función firstValueFrom() convierte el observable en una promesa que se resuelve con el primer valor emitido.

Peticiones POST con datos

Para realizar peticiones POST con datos, el proceso es similar pero incluyendo el cuerpo de la petición:

@Injectable()
export class ApiService {
  constructor(private readonly httpService: HttpService) {}

  async createUser(userData: any): Promise<any> {
    try {
      const response = await firstValueFrom(
        this.httpService.post(
          'https://jsonplaceholder.typicode.com/users',
          userData,
          {
            headers: {
              'Content-Type': 'application/json',
            },
          }
        )
      );
      return response.data;
    } catch (error) {
      throw new Error(`Error al crear usuario: ${error.message}`);
    }
  }
}

Configuración dinámica con ConfigService

Para aplicaciones más robustas, es recomendable utilizar el ConfigService para manejar la configuración de forma dinámica:

import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    HttpModule.registerAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        timeout: configService.get('HTTP_TIMEOUT', 5000),
        baseURL: configService.get('API_BASE_URL'),
        headers: {
          'Authorization': `Bearer ${configService.get('API_TOKEN')}`,
        },
      }),
      inject: [ConfigService],
    }),
  ],
  providers: [ApiService],
})
export class ApiModule {}

Esta configuración permite cargar valores desde variables de entorno o archivos de configuración, haciendo la aplicación más flexible y segura.

Interceptors de Axios para tracing y reintentos

Axios expone interceptors.request y interceptors.response que se configuran sobre la instancia interna del HttpService. Útil para añadir tracing, reintentos con backoff o autenticación dinámica:

@Injectable()
export class ExternalApiService {
  constructor(private readonly http: HttpService) {
    this.http.axiosRef.interceptors.request.use((config) => {
      config.headers['x-trace-id'] = traceContext.getStore()?.traceId ?? crypto.randomUUID();
      return config;
    });
    this.http.axiosRef.interceptors.response.use(
      (res) => res,
      async (error) => {
        const cfg = error.config;
        cfg.__retryCount = (cfg.__retryCount ?? 0) + 1;
        if (cfg.__retryCount > 3 || error.response?.status < 500) throw error;
        await new Promise((r) => setTimeout(r, 2 ** cfg.__retryCount * 250));
        return this.http.axiosRef(cfg);
      },
    );
  }
}

Esto añade reintento exponencial automático en errores 5xx y red, sin contaminar cada llamada con boilerplate.

Manejo de errores tipados con AxiosError

Importar AxiosError permite capturar respuestas de error con tipado:

import { AxiosError } from 'axios';

async getOrder(id: string) {
  try {
    const res = await firstValueFrom(this.http.get<Order>(`/orders/${id}`));
    return res.data;
  } catch (error) {
    if (error instanceof AxiosError) {
      if (error.response?.status === 404) throw new NotFoundException(`Order ${id}`);
      if (error.response?.status === 401) throw new UnauthorizedException('Token expirado');
    }
    throw new BadGatewayException('Error contactando servicio externo');
  }
}

Resilience patterns: Circuit Breaker

Para integraciones críticas conviene combinar HttpModule con un circuit breaker como opossum. Cuando el endpoint externo cae, el circuit breaker abre y devuelve un fallback inmediato sin saturar al servicio caído:

import CircuitBreaker from 'opossum';

@Injectable()
export class PaymentGatewayClient {
  private breaker: CircuitBreaker;

  constructor(private readonly http: HttpService) {
    this.breaker = new CircuitBreaker(
      (payload: PaymentDto) =>
        firstValueFrom(this.http.post('/charges', payload)),
      { timeout: 5000, errorThresholdPercentage: 50, resetTimeout: 30_000 },
    );
    this.breaker.fallback(() => ({ status: 'queued', retryLater: true }));
  }

  charge(dto: PaymentDto) {
    return this.breaker.fire(dto);
  }
}

Métricas y observabilidad

Cada llamada externa debe registrar:

  • Histograma de latencia (http_client_duration_seconds) etiquetado por servicio y endpoint.
  • Contador de errores (http_client_errors_total) con label status_code.
  • Throughput (http_client_requests_total).

Estas métricas alimentan SLOs de "% peticiones bajo 1s" y dashboards Grafana que evidencian degradación antes de que el cliente lo note.

Alternativas a HttpModule

HttpModule es ideal para la mayoría de casos, pero existen alternativas:

  • undici (cliente HTTP nativo de Node 18+): mejor rendimiento, soporte HTTP/2 puro. Útil cuando se buscan latencias mínimas.
  • got: API más moderna basada en Promises, con reintentos y hooks integrados.
  • fetch nativo (Node 18+): para integraciones simples sin dependencias.

HttpModule aporta la integración con DI, interceptors automáticos y la API observable de RxJS; en proyectos NestJS sigue siendo la opción recomendada salvo necesidades muy específicas de rendimiento.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en Nest

Documentación oficial de Nest
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Nest es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Nest

Explora más contenido relacionado con Nest y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Comprender la integración del módulo HTTP de NestJS con axios. Aprender a instalar y configurar el HttpModule en un proyecto NestJS. Entender cómo inyectar y utilizar HttpService para realizar peticiones HTTP. Manejar respuestas usando operadores de RxJS y convertir observables en promesas. Configurar dinámicamente el módulo HTTP usando ConfigService para mayor flexibilidad.