Uso de HttpModule en NestJS para comunicación de microservicios
La comunicación entre microservicios es una de los principales desafíos de esta arquitectura y al trabajar con NestJS, este ofrece un módulo llamado HttpModule que se utiliza para realizar solicitudes HTTP. En este artículo, explicaré cómo integrar y utilizar este módulo en tu aplicación NestJS.
¿Qué es NestJS?
NestJS es un framework de back-end construido sobre Node.js. Utiliza TypeScript por defecto y ofrece un conjunto de herramientas para construir aplicaciones de servidor eficientes y escalables. Su arquitectura modular y sistema de inyección de dependencias permiten una fácil integración de diferentes módulos, incluido el HttpModule.
NestJS combina elementos de la programación orientada a objetos, funcional y reactiva, proporcionando una base sólida para la construcción de microservicios que pueden operar y escalar de manera independiente.
¿Qué es HttpModule?
HttpModule es una utilidad en NestJS que facilita la realización de solicitudes HTTP. Está basado en la biblioteca Axios y se integra perfectamente con los servicios de NestJS. Lo especial de HttpModule
es que, en lugar de trabajar con promesas, trabaja con observables. Estos observables provienen de la biblioteca RxJS y permiten una mayor flexibilidad y control sobre las operaciones asíncronas, como las solicitudes HTTP.
Instalación y Configuración
Para comenzar a utilizar NestJS y HttpModule, primero deberás instalar el CLI de NestJS. Luego, podrás importar el HttpModule en el módulo de tu aplicación, yo estoy suponiendo que si has llegado a este artículo, es porque ya tienes tu aplicación montada y solo buscas entender como funciona el módulo de http.
// Instalación de NestJS CLI
npm i -g @nestjs/cli
// Crear una nueva aplicación
nest new my-nest-app
// Importar HttpModule en app.module.ts
import { HttpModule } from '@nestjs/common';
import { MiServicio } from './MiServicio';
@Module({
imports: [HttpModule],
providers: [MiServicio]
})
export class AppModule {}
Utilizando HttpModule
Este es un ejemplo de cómo realizar una solicitud vía POST hacia un endpoint que me he inventado, utiliza el método pipe
y el operador catchError
para el manejo de errores.
import { HttpService } from '@nestjs/axios';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { catchError, firstValueFrom, map } from 'rxjs';
@Injectable()
export class MiServicio {
private readonly logger = new Logger(MiServicio.name);
private requestConfig: (type: 'JSON' | 'FORM') => AxiosRequestConfig;
/**
* Constructor
**/
constructor(private httpService: HttpService) {
// Configuración de la petición HTTP
this.requestConfig = (type: 'JSON' | 'FORM'): AxiosRequestConfig => {
const baseHeaders = {
'Accept': 'application/json',
'Content-Type': type === 'JSON' ? 'application/json' : 'application/x-www-form-urlencoded',
'User-Agent': 'nombre_de_tu_aplicacion'
};
return {
baseURL: 'http://ejemplo.com',
headers: baseHeaders,
};
};
}
/**
* ejemploPost
**/
async ejemploPost(uuid: string, data: Record<string, string | number >): Promise<boolean> {
return firstValueFrom(
this.httpService
.post<boolean>(`/api/data/${uuid}`, data, this.requestConfig('JSON'))
.pipe(
map((res: AxiosResponse<boolean>) => res.data),
catchError((error: AxiosError) => {
throw error;
}),
)
).catch((error: AxiosError) => {
this.logger.error(error);
throw error;
});
}
}
El HttpModule
retorna observables cuando se hacen solicitudes. Un observable es una secuencia de datos que pueden llegar con el tiempo. Con los observables, puedes usar operadores como pipe
para transformar o manipular esos datos, o incluso manejar errores. El operador pipe
permite encadenar múltiples operadores para actuar sobre los valores emitidos por el observable. En el ejemplo anterior, estamos utilizando pipe
para transformar la respuesta y manejar errores.
Comentarios adicionales sobre los operadores y funciones de RxJS
firstValueFrom
Cuando trabajamos con observables, a menudo necesitamos extraer el primer valor emitido y luego completar automáticamente el observable. Esto es especialmente útil cuando trabajamos con llamadas HTTP, donde generalmente sólo nos interesa la respuesta inicial. La función firstValueFrom
de RxJS nos permite hacer precisamente eso.
import { firstValueFrom } from 'rxjs';
const observableData = this.httpService.get('/api/data');
const data = await firstValueFrom(observableData);
En el código anterior, firstValueFrom
toma el observable observableData
y devuelve una promesa que resuelve con el primer valor emitido por el observable.
map
El operador map
es similar a la función map
de JavaScript para arrays, pero se aplica a observables. Nos permite transformar los datos emitidos por un observable antes de que lleguen al suscriptor.
import { map } from 'rxjs/operators';
this.httpService.get('/api/data').pipe(
map(response => response.data)
);
En el ejemplo anterior, estamos usando map
para extraer la propiedad data
de la respuesta HTTP.
catchError
Las operaciones asincrónicas, como las solicitudes HTTP, pueden fallar por diversas razones. El operador catchError
nos permite manejar errores en nuestro flujo de observables. Nos proporciona el error que ocurrió y nos permite devolver un nuevo observable o arrojar un error.
import { catchError } from 'rxjs/operators';
this.httpService.get('/api/data').pipe(
catchError(error => {
console.error('Error fetching data:', error);
throw new Error('Failed to fetch data');
})
);
En este ejemplo, estamos capturando cualquier error que ocurra durante la llamada HTTP y luego mostrando un mensaje de error en la consola y arrojando un nuevo error.
NestJS y su HttpModule representan una combinación poderosa para la construcción de microservicios robustos y eficientes. El uso de observables y el sistema modular de NestJS permiten una comunicación fluida entre servicios, optimizando el rendimiento y la escalabilidad de tus aplicaciones.
Debo dejar claro que no he sugerido que utilices HTTP para resolver la comunicación entre tus microservicios, esta es una de tantas posibles soluciones y obviamente el uso de HTTP agregará un poco de latencia en tus aplicaciones.
Happy coding! :D
Photo by Matt Duncan on Unsplash