Monorepo and Microservice setup in Nest.js
Tags: javascript, beginners, microservices, typescript
Published: 2020-03-08 20:06:39

Let's first define what a monorepo is

> a monorepo (a syllabic abbreviation of a monolithic repository) is a software development strategy where code for many projects is stored in the same repository.

Instead of heaving a git repo for every service or app, we will just have one git repo where everything will be included.

This style of organizing your code has some benefits.
Code reusability is easy since the code is already there. Updating dependencies is also more comfortable when you set up your mono repo correctly. 

Now let's define what are 'microservices'.

> Microservices is a software development technique. A variant of the service-oriented architecture (SOA) structural style— that arranges an application as a collection of loosely coupled services. In a microservices architecture, services are fine-grained, and the protocols are lightweight.

Instead of having everything in one application/service, we have minimal independent services. This can mean that every service has its database, can be written in a different programming language, and also should be easy to replace. Microservices are a hot and significant topic. Like everything, they have cons and pros! If you want to know more about microservices, write it down below in the comments, and I can write more about them in the next blog post!

### Monorepo in nestjs

First, we need to install the Nest CLI.

```bash
npm install -g @nestjs/cli
or
yarn global add @nestjs/cli
```

Now you should have the `nest` command in your terminal.
We can test that with:

```bash
nest --version
```

Now we can create a "standard" project with

```bash
nest new lampeweb
```

You can either choose if you want to use `npm` or `yarn`. Since I like to use `yarn`, I always select yarn.

Now that we have created a standard project, we need to turn this project into a monorepo. This is pretty simple with nest we just need to run the following command:

```bash
cd lampeweb
nest generate app blog
```

That's it! Now we have a monorepo. As you can see, the `src` folder is gone, and we now have an `apps` folder. In the `apps` folder, we can now find both of our applications/microservices.

One important file is the `nest-cli.json` file. When you open that file, you can see a JSON configuration file with a lot of entries. The import entries for us are `"root": "apps/lampeweb",`. This entry tells the Nest CLI where the main file of that project is. Also, you can find the `"projects": {` entry. Here we can find a list of every app/service in that project. 


Before we can do that, we need to change the port of our `blog` app.

open `apps/blog/src/main.ts` and change the following line:
```js
await app.listen(3000);
```
to
```js
await app.listen(4000);
```

now let's start our services.
```bash
nest start
```
and in a second terminal
```bash
nest start blog
```

So the first command will start our `root` app. In our case, this is the `lampeweb` app. The second command will start the blog service. Easy, right?

Now we have two apps running in a mono repo!

### Microservices

The first thing we have to do is to add the Nest microservice package to our project.

```bash
yarn add @nestjs/microservices
```

First, we need to edit `apps/blog/src/main.ts`

```ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Transport } from '@nestjs/microservices';
import { Logger } from '@nestjs/common';

const logger = new Logger('Blog');

async function bootstrap() {
  const app = await NestFactory.createMicroservice(AppModule, {
    transport: Transport.TCP,
    options: {
      port: 4000,
    },
  });
  await app.listen(() => logger.log('Microservice is listening'));
}
bootstrap();
```

We changed `NestFactory.create` to `NestFactory.createMicroservice`. This will tell Nest that this app now is a microservice. We now also have a configuration JSON. We need to tell Nest what transport method we want to use. `TCP` is the simplest one and does not need any extras. We can also use `Redis`, `RabbitMQ`, and many more. If there is enough interest in this article, then I can go into more detail about that topic. We also need to add the port to the configuration JSON.

The second file in that app/service/microservice we need to edit is `apps/blog/src/app.controller.ts`.

We need to change
```ts
  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
```
to
```ts
  @MessagePattern('getHello')
  getHello(name: string): string {
    return this.appService.getHello(name);
  }
```
Now we don't have an http verb anymore but `MessagePattern`. With the `'getHello'` name we can later call that function.

The third file we want to change is `apps/blog/src/app.service.ts`
We need to change
```ts
@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}
```
to
```ts
@Injectable()
export class AppService {
  getHello(name: string): string {
    return `Hello ${name}!`;
  }
}
```
So that this getHello message accepts a string so that we can return the name back.
That's it! Our `blog` microservice is done.

In our `lampeweb` app, we need to change the following file `apps/lampeweb/src/app.service.ts`.
From
```ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

```
to
```ts
import { Injectable } from '@nestjs/common';
import {
  ClientProxyFactory,
  Transport,
  ClientProxy,
} from '@nestjs/microservices';

@Injectable()
export class AppService {
  private client: ClientProxy;

  constructor() {
    this.client = ClientProxyFactory.create({
      transport: Transport.TCP,
      options: {
        port: 4000,
      },
    });
  }

  public getHello(): Promise<string> {
    return this.client.send<string, string>('getHello', 'Michael').toPromise();
  }
}

```

Okay, this looks like a lot! We added a `constructor` method that created our client. We need to tell our client what transport and what port the microservice we want to connect to uses. In a real-world app, you also need to provide the host, but we are skipping that here because this runs on the same machine.

We now just need to modify our `getHello` method to return a promise. The `send` method takes two parameters. The first one is the name of the message we are sending, and the second one is the payload we want to send. In our case, just a simple string with a name.

The next file we need to change is `apps/lampeweb/src/app.controller.ts` from
```ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
```
to
```ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  async getHello(): Promise<string> {
    const helloValue = await this.appService.getHello();
    return helloValue;
  }
}

```

Not much has changed just that we are now expecting a promise to be resolved to a string.

That's it!
Now you need to restart both services:
```bash
nest start
#and
nest start blog
```
If you want, you can also add the `--watch` flag to both commands so nest will rebuild the service every time you save.

Now we just need to open a browser and go to `http://localhost:3000/`.

You should now see the following
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0d0cidtg34o15980nfj6.png)


I hope you liked that post! If you want a follow-up, please comment, like, and share. So I can know that you are interested in content like that!

**👋Say Hello!** [Instagram](https://www.instagram.com/lampewebdev/) | [Twitter](https://twitter.com/lampewebdev) | [LinkedIn](https://www.linkedin.com/in/michael-lazarski-25725a87) | [Medium](https://medium.com/@lampewebdevelopment) | [Twitch](https://dev.to/twitch_live_streams/lampewebdev) | [YouTube](https://www.youtube.com/channel/UCYCe4Cnracnq91J0CgoyKAQ)