Search code examples
controllernestjsmicroservices

NestJs How to use controller on a microservice?


I have a monolith project with 2 microservices using NestJs/Microservices and Redis for connection trough.

What I need to achieve:

  1. create a controller on microservice and handle an endpoint named (/external).

The problem:

  1. controller on microservice dont receive http requests.

Details:

my microservice main.ts:

import { NestFactory } from '@nestjs/core';
import { OfferModule } from './offer.module';
import { Transport, RedisOptions } from '@nestjs/microservices';

async function bootstrap() {
  // const app = await NestFactory.createMicroservice(OfferModule, {
  //   name: 'OFFER_SERVICE',
  //   transport: Transport.REDIS,
  //   options: {
  //     host: process.env.REDIS_HOST || 'redis',
  //     port: process.env.REDIS_PORT || 6379,
  //   },
  // } as RedisOptions);

  const appMicroservice = await NestFactory.create(OfferModule, {
    cors: {
      origin: true,
      credentials: true,
    },
  });

  appMicroservice.connectMicroservice({
    name: 'OFFER_SERVICE',
    transport: Transport.REDIS,
    options: {
      host: process.env.REDIS_HOST || 'localhost',
      port: process.env.REDIS_PORT || 6379,
    },
  });

  await appMicroservice.listen(3000);
}

bootstrap();

my controller offer.controller.ts

import { Body, Controller, Get, Inject, Post } from '@nestjs/common';
import { OfferService } from './offer.service';
import { ClientProxy } from '@nestjs/microservices';
import { OfferMicroserviceEventsEnum } from './enums/offer-microservice-events.enum';
import { lastValueFrom } from 'rxjs';

@Controller('please_work')
export class OfferController {
  constructor(
    private readonly _offerService: OfferService,
    @Inject('OFFER_SERVICE') private readonly client: ClientProxy,
  ) {}

  @Get('/')
  getHello() {
    return 'Hello from offer microservice';
  }
  @Post('/1')
  async completeTask(@Body() data: any) {
    return await lastValueFrom(
      this.client.send(OfferMicroserviceEventsEnum.COMPLETE_TASK, data),
    );
  }
}

im starting my project with docker. Here is my stdout:

[6:18:53 PM] Starting compilation in watch mode...
offer-microservice  | 
offer-microservice  | [6:18:55 PM] Found 0 errors. Watching for file changes.
offer-microservice  | 
offer-microservice  | [Nest] 42  - 10/09/2023, 6:18:55 PM     LOG [NestFactory] Starting Nest application...
offer-microservice  | [Nest] 42  - 10/09/2023, 6:18:55 PM     LOG [InstanceLoader] OfferModule dependencies initialized +33ms
offer-microservice  | [Nest] 42  - 10/09/2023, 6:18:55 PM     LOG [RoutesResolver] OfferController {/please_work}: +9ms
offer-microservice  | [Nest] 42  - 10/09/2023, 6:18:55 PM     LOG [RouterExplorer] Mapped {/please_work, GET} route +1ms
offer-microservice  | [Nest] 42  - 10/09/2023, 6:18:55 PM     LOG [RouterExplorer] Mapped {/please_work/1, POST} route +0ms
offer-microservice  | [Nest] 42  - 10/09/2023, 6:18:55 PM     LOG [NestApplication] Nest application successfully started +2ms

As we can see the route is mapped , but however im trying to access it im getting 404. (get request to: http://localhost:3000/please_work)

enter image description here

Edit:

docker-compose file:

version: "3.8"

services:
  offer-microservice:
    container_name: offer-microservice
    build:
      context: .
    volumes:
      - .:/usr/src/app
    entrypoint: [ "yarn", "start:dev" ]
    networks:
      - test

networks:
  test:
    external: true

Solution

  • You need to add the ports to your docker-compose so that docker knows to map your machine's port 3000 to this container's port 3000. Your new docker-compose should look something like this:

    version: "3.8"
    
    services:
      offer-microservice:
        container_name: offer-microservice
        build:
          context: .
        volumes:
          - .:/usr/src/app
        entrypoint: [ "yarn", "start:dev" ]
        networks:
          - test
        ports
          - '3000:3000'
    
    networks:
      test:
        external: true
    

    The external option of the network is probably not what you expect it to be, as it means that you're using a network created outside of the docker compose application. Unless you specifically have a Docker network set up that you plan to use, you can remove that option. The added ports section is still necessary though, so that your local machine knows where to send requests to port 3000