🦁

NestJSでREST(その3)

2023/04/13に公開

前回まで

https://zenn.dev/robon/articles/32bf49163826ca

TypeORMとPostgresの設定ができました。👏

TypeORMを使って、モジュールを完成させる

NestJSは、DIなので依存関係はうるさくないのですが、下からやります。(実は、ORMだけじゃなくてDIも嫌いです。)

service

データベース呼び出しはTypeORMがやってくれる(はずな)ので、serviceは、TypeORM呼び出しをやります。

src/customers/customers.service.ts
@@ -1,26 +1,70 @@
-import { Injectable } from '@nestjs/common';
+import {
+  Injectable,
+  NotFoundException,
+  InternalServerErrorException,
+} from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { DeleteResult, Repository } from 'typeorm';
 import { CreateCustomerDto } from './dto/create-customer.dto';
 import { UpdateCustomerDto } from './dto/update-customer.dto';
+import { Customer } from './entities/customer.entity';
 
 @Injectable()
 export class CustomersService {
-  create(createCustomerDto: CreateCustomerDto) {
-    return 'This action adds a new customer';
+  constructor(
+    @InjectRepository(Customer)
+    private customersRepository: Repository<Customer>,
+  ) {}
+
+  async create(createCustomerDto: CreateCustomerDto): Promise<Customer> {
+    return await this.customersRepository.save(createCustomerDto).catch((e) => {
+      throw new InternalServerErrorException(e.message);
+    });
   }
 
-  findAll() {
-    return `This action returns all customers`;
+  async findAll(): Promise<Customer[]> {
+    return await this.customersRepository.find().catch((e) => {
+      throw new InternalServerErrorException(e.message);
+    });
   }
 
-  findOne(id: number) {
-    return `This action returns a #${id} customer`;
+  async findOne(id: number): Promise<Customer> {
+    const customer = await this.customersRepository.findOneBy({
+      customerId: id,
+    });
+    if (!customer) {
+      throw new NotFoundException(`Customer not found (${id})`);
+    }
+    return customer;
   }
 
-  update(id: number, updateCustomerDto: UpdateCustomerDto) {
-    return `This action updates a #${id} customer`;
+  async update(
+    id: number,
+    updateCustomerDto: UpdateCustomerDto,
+  ): Promise<Customer> {
+    await this.customersRepository
+      .update({ customerId: id }, updateCustomerDto)
+      .catch((e) => {
+        throw new InternalServerErrorException(e.message);
+      });
+    const customer = await this.customersRepository.findOneBy({
+      customerId: id,
+    });
+    if (!customer) {
+      throw new NotFoundException(`Customer not found (${id})`);
+    }
+    return customer;
   }
 
-  remove(id: number) {
-    return `This action removes a #${id} customer`;
+  async remove(id: number): Promise<DeleteResult> {
+    const result = await this.customersRepository
+      .delete({ customerId: id })
+      .catch((e) => {
+        throw new InternalServerErrorException(e.message);
+      });
+    if (!result.affected) {
+      throw new NotFoundException(`Customer not found (${id})`);
+    }
+    return result;
   }
 }

長いのですが、上から、constructorでRepositoryをインジェクションします。

そして、create 以下の全メソッドをasyncにして、戻りをPromiseにします。
これは、TypeORMのRepositoryのメソッドがPromiseを返してくれる非同期のメソッドなので、awaitで非同期関数内で同期します。(Node.jsが高速なのは非同期のおかげだと思うので、非同期が難しくても頑張ってついていきましょう)

あとは、返したいStatusCodeに対応する例外を発生させます。

controller

controllerは、serviceを呼び出しますが、serviceのメソッドが非同期になったので、controllerも非同期にします。

src/customers/customers.controller.ts
@@ -1,34 +1,49 @@
-import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Put,
+  Param,
+  Delete,
+} from '@nestjs/common';
+import { DeleteResult } from 'typeorm';
 import { CustomersService } from './customers.service';
 import { CreateCustomerDto } from './dto/create-customer.dto';
 import { UpdateCustomerDto } from './dto/update-customer.dto';
+import { Customer } from './entities/customer.entity';
 
 @Controller('customers')
 export class CustomersController {
   constructor(private readonly customersService: CustomersService) {}
 
   @Post()
-  create(@Body() createCustomerDto: CreateCustomerDto) {
-    return this.customersService.create(createCustomerDto);
+  async create(
+    @Body() createCustomerDto: CreateCustomerDto,
+  ): Promise<Customer> {
+    return await this.customersService.create(createCustomerDto);
   }
 
   @Get()
-  findAll() {
-    return this.customersService.findAll();
+  async findAll(): Promise<Customer[]> {
+    return await this.customersService.findAll();
   }
 
   @Get(':id')
-  findOne(@Param('id') id: string) {
-    return this.customersService.findOne(+id);
+  async findOne(@Param('id') id: string): Promise<Customer> {
+    return await this.customersService.findOne(+id);
   }
 
-  @Patch(':id')
-  update(@Param('id') id: string, @Body() updateCustomerDto: UpdateCustomerDto) {
-    return this.customersService.update(+id, updateCustomerDto);
+  @Put(':id')
+  async update(
+    @Param('id') id: string,
+    @Body() updateCustomerDto: UpdateCustomerDto,
+  ): Promise<Customer> {
+    return await this.customersService.update(+id, updateCustomerDto);
   }
 
   @Delete(':id')
-  remove(@Param('id') id: string) {
-    return this.customersService.remove(+id);
+  async remove(@Param('id') id: string): Promise<DeleteResult> {
+    return await this.customersService.remove(+id);
   }
 }

あとは、オリジナルはupdateのHTTPメソッドがPatchだったのですが、Putにしちゃいました。

module

TypeORMのCustomerの機能をインポートします。

src/customers/customers.module.ts
@@ -1,9 +1,12 @@
 import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
 import { CustomersService } from './customers.service';
 import { CustomersController } from './customers.controller';
+import { Customer } from './entities/customer.entity';
 
 @Module({
+  imports: [TypeOrmModule.forFeature([Customer])],
   controllers: [CustomersController],
-  providers: [CustomersService]
+  providers: [CustomersService],
 })
 export class CustomersModule {}

次回は

途中で書いた「設定が丸見えなの」をなんとかして、最初に「やりたいこと」で書いた全体を仕上げて、全体のソースコードも公開したいと思います。

https://zenn.dev/robon/articles/3f277a2b1b95a3

GitHubで編集を提案
株式会社ROBONの技術ブログ

Discussion