I'm trying to do what I think it's a stupid simple endpoint and some how it seems nestjs is not resolving the observable from Axios which results in the request hanging until it reaches the timeout. I've stripped down my entire application to barebones, literally, in the pursuit of the issue and I still can't really find anything....
main.ts:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(8080);
}
bootstrap();
app.module.ts:
import { Module } from '@nestjs/common';
import { AuthModule } from './auth/authModule';
@Module({
imports: [AuthModule],
})
export class AppModule {}
AuthModule.ts:
import { Module } from '@nestjs/common';
import { AuthController } from './controllers/auth.controller';
import { HttpModule } from '@nestjs/axios';
@Module({
controllers: [AuthController],
imports: [HttpModule],
})
export class AuthModule {}
Auth.controller.ts:
import { Controller, Post } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Observable } from 'rxjs';
import { AxiosResponse } from 'axios';
@Controller('auth')
export class AuthController {
constructor(private httpService: HttpService) {}
@Post('/login')
login(): Observable<AxiosResponse<string>> {
console.log('hit');
return this.httpService.get<string>('http://auth-ms/health');
}
}
package.json:
"dependencies": {
"@liaoliaots/nestjs-redis": "^8.2.1",
"@metamask/eth-sig-util": "^4.0.0",
"@nestjs/axios": "^0.0.8",
"@nestjs/common": "^8.0.0",
"@nestjs/config": "^2.0.0",
"@nestjs/core": "^8.0.0",
"@nestjs/platform-express": "^8.0.0",
"@nestjs/typeorm": "^8.1.4",
"axios": "^0.27.2",
"faker": "^6.6.6",
"ioredis": "^5.0.3 || ^0.3.6",
"jsonwebtoken": "^8.5.1",
"jwt-decode": "^3.1.2",
"nestjs-ethers": "^1.0.1",
"nestjs-real-ip": "^2.1.0",
"pg": "^8.7.3",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"typeorm": "^0.3.6",
},
Any clue on what's going on here? I guess I'm missing something small and stupid but... can't really figure out what.
CodePudding user response:
So, AxiosResponse is a complex data structure and contains circular dependencies.
So you need to map it because you can't return it like this (except if you use a lib that parse circular JSON)
So you need to map the observable to only get the data of the website.
@Post('/login')
login(): Observable<string> {
console.log('hit');
return this.httpService
.get<string>('http://auth-ms/health')
.pipe(map((v) => v.data));
}
CodePudding user response:
The Observable class works like a Promise and it handles I/O commands asynchronously by default. To return the result from a gateway request, like you are trying to do, you'll need to resolve the Observable synchronously.
To do it, you need to use the firstValueFrom
or lastValueFrom
functions from rxjs
lib to convert it to a Promise and await
the response:
import { Controller, Post } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Observable, firstValueFrom } from 'rxjs';
import { AxiosResponse } from 'axios';
@Controller('auth')
export class AuthController {
constructor(private httpService: HttpService) {}
@Post('/login')
async login(): Promise<string> {
const responseObserver = this.httpService.get<string>('http://auth-ms/health');
const response = await firstValueFrom(responseObserver);
return response.data;
}
}