Customer: Use Case (3: Implementing NestJS Service)
Tags: beginners, tutorial, typescript, nestjs
Published: 2023-11-30 01:03:45

## Prerequisites
1. Installed Node version of `v20.10.0`
2. Installed PostgreSQL version of `16`

## Initialize NestJS application
I'm assuming that you have already created project directories just like what I did in the first post.
1. Install nest cli globally using `command prompt`.
    ```
     npm i -g @nestjs/cli
    ```
2. Open new `command prompt` from the `nest-service` directory.
3. Create new NestJS project by running command below. I choose `npm` as the package manager.
    ``` 
    nest new .
    ```
4. Install these dependencies:
    #### Dependency to work with .env file
    ```
    npm i --save @nestjs/config
    ```
    #### TypeOrm dependencies
    ```
    npm install @nestjs/typeorm typeorm
    ```
    #### PostgreSQL dependency
    ```
    npm install pg
    ```
    My `package.json` dependencies looks like:
    ```
     "dependencies": {
        "@nestjs/common": "^10.0.0",
        "@nestjs/config": "^3.1.1",
        "@nestjs/core": "^10.0.0",
        "@nestjs/platform-express": "^10.0.0",
        "@nestjs/typeorm": "^10.0.1",
        "pg": "^8.11.3",
        "reflect-metadata": "^0.1.13",
        "rxjs": "^7.8.1",
        "typeorm": "^0.3.17"
    }
    ```
4. Create project directory skeleton that looks like this:
    ```
    nest-service/
    ├── src/
    │   ├── config/
    │   ├── controllers/
    │   ├── entities/
    │   ├── modules/
    │   ├── services/
    │   ├── app.controller.ts
    │   ├── app.module.ts
    │   ├── app.service.ts
    │   └── main.ts
    ├── .env
    └── package.json
    ```

5. My `.env` file looks like below. Makesure that you have correct and working port and credentials.
    ```
    PORT=3002
    DB_HOST=localhost
    DB_PORT=5432
    DB_USERNAME=postgres
    DB_PASSWORD=password
    DB_NAME=customer
    ```

## Creating configuration
Inside `config` directory, create a file named `database.config.ts` the content will look like this:
```
import { PostgresConnectionOptions } from "typeorm/driver/postgres/PostgresConnectionOptions";
import { ConfigService } from '@nestjs/config';

export const databaseConfig = async (configService: ConfigService): Promise<PostgresConnectionOptions> => ({
  type: 'postgres',
  host: configService.get<string>('DB_HOST'),
  port: parseInt(configService.get<string>('DB_PORT')),
  username: configService.get<string>('DB_USERNAME'),
  password: configService.get<string>('DB_PASSWORD'),
  database: configService.get<string>('DB_NAME'),
  entities: ["dist/**/*.entity{.ts,.js}"],
  synchronize: false,
});
```

## creating entities
Now, let's move on to `entities` directory. Create a file called `Customer.enitity.ts`.
```
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";

@Entity('customers')
export class Customer {
  
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  no: string;

  @Column()
  nama: string;

  @Column()
  alamat: string

  @Column()
  kota: string

  @CreateDateColumn()
  createdAt: Date

  @UpdateDateColumn()
  updatedAt: Date;

}
```

## Creating services
In services we are going to create a file named `customer.service.ts` and the content is looks like this:
```
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { randomUUID } from "crypto";
import { Customer } from "src/entities/Customer.entity";
import { Repository } from "typeorm";

export interface CustomerInterface {
  id?: string,
  no?: string, 
  nama: string,
  alamat: string,
  kota: string
  createdAt?: Date;
  updatedAt?: Date;
};

@Injectable()
export class CustomersService {

  constructor(
    @InjectRepository(Customer)
    private customerRepository: Repository<CustomerInterface>
  ) {}

  create(customer: CustomerInterface): Promise<CustomerInterface> {
    const customerBody = this.customerRepository.create(customer);
    customerBody.no = randomUUID();
    customerBody.createdAt = new Date();
    customerBody.updatedAt = new Date();
    return this.customerRepository.save(customerBody);
  }

  findAll(): Promise<CustomerInterface[]> {
    return this.customerRepository.find();
  }

  findById(id: string): Promise<CustomerInterface> {
    return this.customerRepository
      .findOne({
        where: {
          id: id
        }
      });
  }

  update(id: string, data: CustomerInterface): Promise<any> {
    return this.customerRepository
      .createQueryBuilder()
      .update()
      .set({
        nama: data.nama,
        alamat: data.alamat,
        kota: data.kota
      })
      .where('id = :id', { id })
      .execute();
  }

  delete(id: string): Promise<any> {
    return this.customerRepository
      .createQueryBuilder()
      .delete()
      .from(Customer)
      .where('id = :id', { id })
      .execute();
  }
}
```

## Creating controllers
Let's create the controller for customer by making a file called `customer.controller.ts` inside `controllers` directory.
```
import { Body, Controller, Delete, Get, Param, Post, Put } from "@nestjs/common";
import { CustomerInterface, CustomersService } from "src/services/customer.service";

interface CreateCustomerDto {
  nama: string,
  alamat: string,
  kota: string
};

@Controller('api/customers')
export class CustomersController {

  constructor(private customerService: CustomersService) {}

  @Post()
  async create(@Body() createCustomerDto: CreateCustomerDto) {
    const customer = await this.customerService.create(createCustomerDto);

    if(!customer) {
      return 'Error creating customer';
    }

    return 'Customer created successfully';
  }

  @Get()
  async findAll() {
    const customers: Array<CustomerInterface> = await this.customerService.findAll();

    return customers;
  }

  @Get(':id')
  async findByNama(@Param('id') id: string ) {
    const customer: CustomerInterface = await this.customerService.findById(id);

    return customer;
  }

  @Put(':id')
  async update(@Param('id') id: string, @Body() body: CustomerInterface) {
    const newCustomer: CustomerInterface = await this.customerService.update(id, body);
    
    if(!newCustomer) {
      return 'Error updating customer';
    }

    return 'Customer updated successfully';
  }

  @Delete(':id')
  async remove(@Param('id') id: string) {
    await this.customerService.delete(id);

    return 'Successfully deleted customer with id' + id;
  }

}
```

## Creating module
Last, we need to pool our `entity`, `controller`, and `service` at the `module`. Create a file called `customer.module.ts` inside `modules` directory.
```
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CustomersController } from 'src/controllers/customer.controller';
import { Customer } from 'src/entities/Customer.entity';
import { CustomersService } from 'src/services/customer.service';

@Module({
  imports: [TypeOrmModule.forFeature([Customer])],
  controllers: [CustomersController],
  providers: [CustomersService]
})

export class CustomersModule {}
```

## Configuring customer module in main module
In `app.module.ts` file which located in root directory, we will configuring the things we've created like this:
```
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CustomersModule } from './modules/customer.module';
import { databaseConfig } from './config/database.config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => await databaseConfig(configService),
    }),
    CustomersModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

## Running application
1. Back to `nest-service` root directory, open command prompt directed to the directory.
2. Run `npm run start`. It will take a little longer.
3. If it is running correctly you will see this log:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8bku5x0oe5nvwki2zpu.png)
4. Test your API endpoints using Postman or Thunder Client.