0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘録】NestJS + TypeORM + Neon(Postgres DBaaS) でCRUDする

Last updated at Posted at 2024-08-11

はじめに

Nest CLIでスケルトンを作成した状態でのスタートです。
Nest v10.4.2
TypeORM 0.3系

ライブラリのインストール

npm install @nestjs/typeorm typeorm pg
npm install ts-node
npm install class-validator class-transformer

1.TypeORMにNeonの接続情報をロードする

1. NeonのダッシュボードからPostgresの接続アドレスを取得する
2. .envに記載する
3. app.module.tsからロードする設定を作成する
4. 作成した設定app.module.tsからロードする

src/config/typeormConfig.ts
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
import { config } from 'dotenv';

config({ path: ".env" })

export const typeOrmConfig: TypeOrmModuleOptions = {
    type: "postgres",
    url: process.env.DB_URL,
    synchronize: true, // 開発環境下のみtrueにしておく
}
src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { typeOrmConfig } from 'src/config/typeormConfig';

@Module({
  imports: [
    TypeOrmModule.forRoot(typeOrmConfig)
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

2.Entityを作ってmigrationする

1. Entityを作成する

src/entity/product.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Product {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ nullable: true })
  imageSrcPath: string | null;

  @Column({ nullable: true })
  deployUrl: string | null;

  @Column()
  productName: string;

  @Column()
  overview: string;

  @Column()
  mainTechnology: string;

  @Column({ nullable: true })
  subTechnology: string | null;

  @Column('text', { array: true })
  productLinks: string[] | null;
}

2. migrationするための接続ファイルを書く

src/ormconfig.ts
import { config } from 'dotenv';
import { DataSource } from 'typeorm';

config({ path: '.env' });

export const dataSource = new DataSource({
  type: 'postgres',
  url: process.env.DB_URL,
  entities: ['src/entity/*.entity.ts'],
  migrations: ['src/migration/*.ts'],
});

3.entity -> migrationファイルの作成を行う

・package.jsonに追記

package.json
"scripts": {
    "typeorm": "typeorm-ts-node-commonjs -d ./src/config/ormconfig.ts"
}

・migrationファイルを生成する

npm run typeorm migration:generate .\src\migration\addNullable

4.migarationファイル -> DBに反映する

npm run typeorm migration:run

3. DTO作ってリクエストのバリデーションを行う

1. main.tsにvalidationPipeを適用する

src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();

2. DTOを作ってvalidationを作成する

src/dto/CreateProductDto.ts
import {
  IsArray,
  IsNotEmpty,
  IsOptional,
  IsString,
  IsUrl,
} from 'class-validator';

export class CreateProductDto {
  @IsOptional()
  @IsString()
  imageSrcPath: string | null;

  @IsOptional()
  @IsUrl()
  deployUrl: string | null;

  @IsString()
  @IsNotEmpty()
  productName: string;

  @IsString()
  @IsNotEmpty()
  overview: string;

  @IsString()
  @IsNotEmpty()
  mainTechnology: string;

  @IsOptional()
  @IsString()
  subTechnology: string | null;

  @IsOptional()
  @IsArray()
  @IsUrl({}, { each: true })
  productLinks: string[] | null;
}

4.エンドポイントを作成してCRUDを通す

1. modulecontrollerserviceを作成する

nest generate module products
nest generate controller products
nest generate service products

2. moduleTypeORMを読み込む

src/products/products.module.ts
import { Module } from '@nestjs/common';
import { ProductsController } from './products.controller';
import { ProductsService } from './products.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Product } from 'src/entity/product.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Product])],
  controllers: [ProductsController],
  providers: [ProductsService],
})
export class ProductsModule {}

3. controllerにルーティングメソッドを追加する

src/products/products.controller.ts
import { Body, Controller, Get, Post, Put } from '@nestjs/common';
import { ProductsService } from './products.service';
import { CreateProductDto } from 'src/dto/CreateProductDto';
import { UpdateProductDto } from 'src/dto/UpdateProductDto';

@Controller('products')
export class ProductsController {
  constructor(private readonly ProductsService: ProductsService) {}

  @Get()
  async readAll() {
    return await this.ProductsService.read();
  }

  @Post()
  async create(@Body() CreateProductDto: CreateProductDto) {
    return await this.ProductsService.create(CreateProductDto);
  }

  @Put()
  async update(@Body() updateProductDto: UpdateProductDto) {
    return await this.ProductsService.update(updateProductDto);
  }
}

4. servicecontrollerから呼び出されるロジックをメソッドとして追加する

src/products/products.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CreateProductDto } from 'src/dto/CreateProductDto';
import { UpdateProductDto } from 'src/dto/UpdateProductDto';
import { Product } from 'src/entity/product.entity';
import { Repository } from 'typeorm';

@Injectable()
export class ProductsService {
  constructor(
    @InjectRepository(Product)
    private productsRepository: Repository<Product>,
  ) {}

  async read() {
    const productsData = await this.productsRepository.find({
      order: {
        id: "ASC"
      }
    });

    const formattedProductData = productsData.map((productData) => ({
      ...productData,
      overview: productData.overview.split(","),
      mainTechnology: productData.mainTechnology.split(","),
      subTechnology: productData.subTechnology.split(",")
    }));

    return formattedProductData;
  }

  async create(CreateProductDto: CreateProductDto) {
    return await this.productsRepository.save(CreateProductDto);
  }

  async update(updateProductDto: UpdateProductDto) {
    return await this.productsRepository.update(
      updateProductDto.id,
      updateProductDto,
    );
  }
}

さいごに

学習させていただいた技術記事のリンクです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?