3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NestJS+TypeORM+PostgreSQLでWeb API作成

Last updated at Posted at 2021-09-18

はじめに

Node.js/Express/routing-controllers+TypeScript+TypeORM+PostgreSQLでWeb API作成で、自分なりに納得いく構成で Web API を作成したが、NestJS なるバックエンドフレームワークの存在を知ってしまったので、そちらも試したところ素晴らしかったので採用。今後 TypeScript での Web API 作成は NestJS+TypeORM+PostgreSQL を使っていきたい。実行環境は以下。

  • Node.js: 14.17.6
  • npm: 6.14.15
  • NestJS: 8.0.6
  • typeorm: 0.2.37

NestJS のインストールおよびプロジェクト作成

First steps | NestJS にしたがって、NestJS をインストールし、プロジェクトを作成する。

$ npm install -g @nestjs/cli
$ nest new api

以下コマンドで動作確認を行う。

$ cd api
$ npm run start

# 別ターミナルにて
$ curl http://localhost:3000
Hello World!

typeorm のインストール

TypeORM にしたがって、以下パッケージをインストールする。PostgreSQL 以外の DB と連携する場合は pg ではなく、適切なパッケージをインストールする。

$ npm install typeorm pg
$ npm install -g typeorm
$ npm install @nestjs/typeorm

ディレクトリ構成

NestJS プロジェクトのディレクトリ構成(一部抜粋)は controller, entity, service ごとの単位ではなく、モジュール単位で構成している。NestJS は Angular に強くインスパイアされており、以下の photo のようにモジュール単位での構成を前提にしているためである。実際、後ほど実行する nest generate コマンドはモジュール単位となるようにファイルが作成される。(たとえば nest generate module photo を実行すると、src/photo/photo.module.ts のように photo ディレクトリも合わせて作成される。)

.
├── ormconfig.json              # TypeORM 設定ファイル、package.json と同階層に置く
├── package-lock.json
├── package.json
├── src
│   ├── app.module.ts           # 各モジュールを統合する AppModule
│   ├── main.ts                 # アプリケーションのエントリファイル
│   └── photo
│       ├── photo.controller.ts # PhotoController
│       ├── photo.entity.ts     # Photo
│       ├── photo.module.ts     # PhotoModule
│       └── photo.service.ts    # PhotoService
└── tsconfig.json

以下、簡単に用語を説明する。

  • Entity : モデルを修飾したクラス。このモデルに基づいた DB テーブルを作成でき、データの追加・削除などの操作もできる。
  • Controller : ルートとリクエストに対しての動作を定義したクラス。コントローラに注入されたサービスが実際の処理を行う。
  • Service : 具体的な処理を定義したクラス。レポジトリを使って、エンティティの管理などを行う。
  • Module : 上記のようなクラスをまとめて1つのモジュールとして統合するクラス。結合が疎となるアーキテクチャを実現する。

Photo モジュールの作成

以下で NestJS + TypeORM + PostgreSQL を用いて Photo API を作成していく。(Photo API は TypeORM で例としているものと同じものである。)

大まかな流れは以下の通り。

  1. Photo エンティティの作成
  2. PhotoService の作成
  3. PhotoController の作成
  4. PhotoModule の作成
  5. AppModule への追加
  6. ormconfig.json の作成
  7. 動作確認

1. Photo エンティティの作成

以下コマンドで、photo.entity.ts ファイルを作成する。(エンティティは nest ではなく typeorm に関わる部分であるため、nest generate コマンドが存在しない。先述のディレクトリ構成で述べたように nest generate コマンドをあらかじめ実行しておくと photo ディレクトリも作成されるが、説明する順番の都合上ここでは mkdir コマンドでディレクトリを作成している。)

$ mkdir src/photo
$ touch src/photo/photo.entity.ts

エンティティクラスは以下のように定義した。モデルのプロパティに対して @Column でカラムを指定し、@Entity でモデルをエンティティ化している。(詳細な説明は割愛。)

photo.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

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

    @Column({
        length: 100
    })
    name!: string;

    @Column('text')
    description!: string;

    @Column()
    filename!: string;

    @Column()
    views!: number;

    @Column()
    isPublished!: boolean;
}

2. サービスの作成

以下コマンドで photo.service.ts を作成する。--no-spec は photo.service.spec.ts を作成しないためのオプションである。

$ nest generate service photo --no-spec

サービスクラスは以下のように定義した。@Injectable により他サービスやコントローラに注入可能にしており、@InjectRepository により上記で定義した Photo エンティティのレポジトリを操作可能になる。また具体的な処理として、「写真の追加」と「写真リストの取得」という2つのメソッドを定義している。

photo.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Photo } from './photo.entity';

@Injectable()
export class PhotoService {
  constructor(
    @InjectRepository(Photo)
    private readonly photoRepository: Repository<Photo>
  ) { }

  async addPhoto(photo: Photo) {
    this.photoRepository.save(photo);
  }

  async getPhotoList() {
    return await this.photoRepository.find();
  }
}

3. コントローラの作成

以下コマンドで photo.controller.ts を作成する。

$ nest generate controller photo --no-spec

コントローラクラスは以下のように定義した。@Controller の引数にてルートを指定しており、これにより http://localhost:3000/photo から始まるリクエストに関する処理を以下メソッドで実行する。また上記で作成した PhotoService を注入し、@Post/@Get で修飾することで各メソッドを Post/Get リクエストに対する処理に対応付けている。

photo.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { Photo } from './photo.entity';
import { PhotoService } from './photo.service';

@Controller('photo')
export class PhotoController {
  constructor(private readonly service: PhotoService) { }

  @Post()
  createPhoto(@Body() photo: Photo) {
    this.service.addPhoto(photo);
  }

  @Get()
  getPhotoList() {
    return this.service.getPhotoList();
  }
}

4. モジュールの作成

以下コマンドで photo.module.ts を作成する。

$ nest generate module photo

モジュールクラスは以下のように定義した。@Module にて、使用するコントローラを controllers に、使用するサービスを providers に指定している。また imports にて、TypeORM と連携して Photo エンティティを扱えるようにしている。

photo.module.ts
import { Module } from '@nestjs/common';
import { Photo } from './photo.entity';
import { PhotoController } from './photo.controller';
import { PhotoService } from './photo.service';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forFeature([Photo])],
  controllers: [PhotoController],
  providers: [PhotoService]
})
export class PhotoModule {}

5. App モジュールへ PhotoModule の追加

TypeORM と連携するための TypeOrmModule と、上記で定義した PhotoModule を読み込む。TypeOrmModule.forRoot() の引数にて、接続する DB の情報を設定することもできるが、コードが見づらくなるため後述の ormconfig.json にて設定する。

app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PhotoModule } from './photo/photo.module';

@Module({
  imports: [
    TypeOrmModule.forRoot(),
    PhotoModule
  ]
})
export class AppModule {}

6. ormconfig.json の作成

接続する DB の情報などを設定する ormconfig.json を作成する。コードは以下。

ormconfig.json
{
  "type": "postgres",
  "host": "172.21.0.1",
  "port": 5432,
  "username": "postgres",
  "password": "postgres",
  "database": "test_db",
  "entities": [
    "dist/**/*.entity.js"
  ],
  "synchronize": true
}

Node.js/Express/routing-controllers+TypeScript+TypeORM+PostgreSQLでWeb API作成と同様にしたところ、SyntaxError: Cannot use import statement outside a module というエラーが発生した。こちらを参考に、"entities": ["dist/**/*.entity.js"] としたところ解消した。上記リンクでも述べているため、詳細は割愛。

7. 動作確認

以下コマンドでアプリケーションを起動する。

$ npm run start

あとは curl コマンドや Postman などで、http://localhost:3000/photo に対して Post リクエストや Get リクエストを送れば動作が確認できる。

おわりに

NestJS + TypeORM + PostgreSQL にて、Web API を作成することができた。ひとまずこの組み合わせで納得したので、認証などより複雑な処理を行えるように引き続き勉強していきたい。

3
3
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
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?