Add a NestJS API to a Nx Workspace
Tags: api, nest, nx, node
Published: 2020-08-07 05:03:17

---
title: "Add a NestJS API to a Nx Workspace"
series: "Building API's with NestJS and Nrwl Nx"
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/3lapwr5f7xlnzlqfs7vv.png
published: true
canonical_url: http://beeman.dev/posts/add-a-nestjs-api-to-a-nx-workspace-24f
tags: api, nest, nx, node
---

## Introduction

In this tutorial, we add two _projects_ to the workspace, an _application_ called _api_, and a library called _core_.

In this app, the _Core_ library is responsible for providing the application-wide configuration using the [@nestjs/config](https://github.com/nestjs/config) package. To validate the configuration we configure NestJS Config to use [Joi](https://npm.im/joi).

## 1. Add the Nx Nest plugin.

Nx has a plugin system that provides functionality for various frameworks. There are official ones and community plugins. One of the official ones is the Nest plugin.

Run the following command to install the plugin:

```bash
yarn add -D @nrwl/nest
```

This plugin provides functionality to create Nest applications and libraries. Let's start with the application.

## 2. Create the API.

In this step we create an _application_ called _api_.

### 2.1 Generate the _api_ application

Run the following command to create the application:

```bash
nx generate @nrwl/nest:app api
```

This generates a new application in `apps/api`, and adds it as a _project_ to `workspace.json` and `nx.json`.

### 2.2 Start the dev server

Run the following command to start the application

```bash
nx serve api
```

This starts the development server and the prints the message 'Listening at [http://localhost:3333/api](http://localhost:3333/api)'.

When you open that URL in the browser, you are greeted with the following message:

```json
{
  "message": "Welcome to api!"
}
```

## 3. Create the _core_ library

One of the great things of building an app using Nx Workspace, is that you can separate the functionality of the app into libraries.

This has numerous benefits: it creates a separation of concerns, it allows members of a team to work on parts of the app in isolation with less risk of conflicts, and allows for re-using the libraries in other projects.

### 3.1 Generate the library

Run the following command to create the library:

```bash
nx generate @nrwl/nest:lib core
```

This generates a new library in `libs/core`, adds it as a _project_ to `workspace.json` and `nx.json`.

Additionally, it adds an entry to the _paths_ object in `tsconfig.base.json`, mapping the name `@beehive/core` to path `libs/core/src/index.ts`. This allows for using the library by importing it from the package name `@beehive/core`.

### 3.2 Use the library

Open `apps/api/src/app/app.module.ts` and add the following line on top, next to the other imports:

```typescript
import { CoreModule } from "@beehive/core";
```

Next, add the `CoreModule` to the `imports` array in the `@Module` decorator:

```typescript
@Module({
  imports: [CoreModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

Make sure to stop and start the dev server, so it will pick up the changes made in `tsconfig.base.json`.

When the server restarts, you should see that it loads the `CoreModule`:

    [InstanceLoader] CoreModule dependencies initialized

> 💡 If you don't restart the dev server, it will not pick up the changes made in `tsconfig.base.json` and you will get an error like this:

    ERROR in ./apps/api/src/app/app.module.ts
    Module not found: Error: Can't resolve '@beehive/core'

Time to add some functionality to the _core_ library.

## 4. Add the configuration.

### 4.1 Install the dependencies

Run the following command to install the dependencies and devDependencies:

```bash
yarn add @nestjs/config joi
```

### 4.2 Create the configuration file

Create the directory `libs/core/src/lib/config`, this is where the configuration is stored.

Next, create the file `libs/core/src/lib/config/configuration.ts`, and add the following snippet:

```typescript
export const configuration = () => ({
  environment: process.env.NODE_ENV,
  port: parseInt(process.env.PORT || "3000", 10),
});
```

This file exports a method that returns an object with the configuration for the API.

The configuration object reads the values from the _environment variables_. Because environment variables are always represented as a string, the `port` property converts the value to an integer using `parseInt`.

Because the `process.env.PORT` variable can be undefined, the default string '3000' is provided. Leaving this out will make TypeScript's strict mode unhappy.

### 4.3 Create the validation file

Create the file `libs/core/src/lib/config/validation.ts` and add the following snippet:

```typescript
import * as Joi from "joi";

export const validationSchema = Joi.object({
  NODE_ENV: Joi.string().valid("development", "production", "test").required(),
  PORT: Joi.number().default(3000),
});
```

The validation file exports a schema that uses Joi for validating the _environment variables_.

The `PORT` environment variable validates that the type is a number, and sets the default value.

For the `NODE_ENV` environment variable, the valid options are either `development`, `production` or `test`. We don't provide a default which means we should always apply one explicitly.

### 4.4 Tying it all together

Open `libs/core/src/lib/core.module.ts` and add the following imports at the top:

```typescript
import { ConfigModule } from "@nestjs/config";
import { configuration } from "./config/configuration";
import { validationSchema } from "./config/validation";
```

After that, add a new array called `imports` to the `@Module` decorator, and add the `ConfigModule` like so:

```typescript
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration],
      validationSchema,
    }),
  ],
  controllers: [],
  providers: [],
  exports: [],
})
export class CoreModule {}
```

When you have the server still running, the following error will appear:

    Error: Config validation error: "NODE_ENV" is required

This is because we did not provide a default value for the `NODE_ENV` _environment variable_, which is required.

## 4.5 Add a .env file for development.

The Nest Config module uses dotenv under the hood. This means we can configure the environment using a `.env` file.

Create a new file called `.env` in your project root, and add the following snippet:

```dotenv
NODE_ENV=development
PORT=3000
```

Restart the dev server to make it read the `.env` file.

## 4.6 Update the .gitignore

Best practice is to not commit the `.env` file into git, as it might store sensitive information like API keys or database connections strings.

Open `.gitignore` from your project root and add the following line:

```gitignore
.env
```

> 💡 Because we don't include the _.env_ file in the repository, it's considered a 'best practice' to provide a default _.env.example_ file that can be used as a reference.

## 5. Use the configuration object.

Last thing to do is use the configuration in our api.

Open `apps/api/src/main.ts` and add the following imports at the top:

```typescript
import { ConfigService } from "@nestjs/config";
```

Next, in the body of the `bootstrap` function, add the following to the start of the method, right below the definition of `const app`:

```typescript
const app = await NestFactory.create(AppModule);
const config = app.get(ConfigService);
```

Lastly, we update the method of the `listen` method, and create a new line that invokes `Logger.log`, below the existin gone:

```typescript
Logger.log("Listening at http://localhost:" + port + "/" + globalPrefix);
Logger.log(`Running in ${config.get("environment")} mode`);
```

When you start the dev server again, the following lines should appear in the output:

```bash
Listening at http://localhost:3000/api
Running in development mode
```

Awesome, the system works!

## Summary

In this tutorial we created a Nest application called _api_, and a module called _core_.

The module is responsible for the application configuration and provides validation to make sure the required properties are defined and have the expected value.

We created a `.env` so we can easily apply environment vars during development, and added this file to `.gitignore`.

Lastly, we updated the `main.ts` file to make it use the `ConfigService`.

In the next tutorial, we will add a GraphQL endpoint to our API, stay tuned!

## Thanks!

Thanks for reading my article, I hope it was useful. Feel free to reach out and follow me on [Twitter](https://twitter.com/beeman_nl/) or leave a comment on DEV! 🐝