HTTP module

Axios is rich-feature HTTP client that is widely used in dozens of applications. That’s why Nest wraps this package and exposes it by default as a built-in HttpModule. The HttpModule exports HttpService that simply exposes axios-based methods to perform HTTP request, but also, transforms return types into Observables.

In order to use a HttpService, we need to import HttpModule.

  1. @Module({
  2. imports: [HttpModule],
  3. providers: [CatsService],
  4. })
  5. export class CatsModule {}

info Hint The HttpModule is exposed from @nestjs/common package.

Then, you can inject HttpService. This class is easily accessible from @nestjs/common package.

  1. @@filename()
  2. @Injectable()
  3. export class CatsService {
  4. constructor(private readonly httpService: HttpService) {}
  5. findAll(): Observable<AxiosResponse<Cat[]>> {
  6. return this.httpService.get('http://localhost:3000/cats');
  7. }
  8. }
  9. @@switch
  10. @Injectable()
  11. @Dependencies(HttpService)
  12. export class CatsService {
  13. constructor(httpService) {
  14. this.httpService = httpService;
  15. }
  16. findAll() {
  17. return this.httpService.get('http://localhost:3000/cats');
  18. }
  19. }

All methods return AxiosResponse wrapped with Observable object.

Configuration

Axios gives a bunch of options that you may take advantage of to make your HttpService even more powerful. Read more about them here. To configure underlying library instance, use register() method of HttpModule.

  1. @Module({
  2. imports: [
  3. HttpModule.register({
  4. timeout: 5000,
  5. maxRedirects: 5,
  6. }),
  7. ],
  8. providers: [CatsService],
  9. })
  10. export class CatsModule {}

All these properties will be passed down to the axios constructor.

Async configuration

Quite often you might want to asynchronously pass your module options instead of passing them beforehand. In such case, use registerAsync() method, that provides a couple of various ways to deal with async data.

First possible approach is to use a factory function:

  1. HttpModule.registerAsync({
  2. useFactory: () => ({
  3. timeout: 5000,
  4. maxRedirects: 5,
  5. }),
  6. });

Obviously, our factory behaves like every other one (might be async and is able to inject dependencies through inject).

  1. HttpModule.registerAsync({
  2. imports: [ConfigModule],
  3. useFactory: async (configService: ConfigService) => ({
  4. timeout: configService.getString('HTTP_TIMEOUT'),
  5. maxRedirects: configService.getString('HTTP_MAX_REDIRECTS'),
  6. }),
  7. inject: [ConfigService],
  8. });

Alternatively, you are able to use class instead of a factory.

  1. HttpModule.registerAsync({
  2. useClass: HttpConfigService,
  3. });

Above construction will instantiate HttpConfigService inside HttpModule and will leverage it to create options object. The HttpConfigService has to implement HttpModuleOptionsFactory interface.

  1. @Injectable()
  2. class HttpConfigService implements HttpModuleOptionsFactory {
  3. createHttpOptions(): HttpModuleOptions {
  4. return {
  5. timeout: 5000,
  6. maxRedirects: 5,
  7. };
  8. }
  9. }

In order to prevent the creation of HttpConfigService inside HttpModule and use a provider imported from a different module, you can use the useExisting syntax.

  1. HttpModule.registerAsync({
  2. imports: [ConfigModule],
  3. useExisting: ConfigService,
  4. });

It works the same as useClass with one critical difference - HttpModule will lookup imported modules to reuse already created ConfigService, instead of instantiating it on its own.