nest.js + prisma + fastify + postgresqlでREST APIのCRUDを作成する
概要
node.jsのバックエンドフレームワークnest.jsを使ってREST APIのCRUDを作成します!
ORMにはprisma、DBはpostgresqlを使って作成します
この記事はnest.js 公式を参考に作成しているので、
詳しく調べたい場合は公式ページの方をみて頂けると良いと思います!
nest.jsのセットアップ
nest.jsのインストールにはnest.js用のCLIがあるのでそれを使用しましょう
npm、yarnのどちらかで使用できます
$ yarn global add @nestjs/cli
# プロジェクトを作る
$ nest new nestjs-prisma-crud
# カレントディレクトリに作る場合
$ nest new .
yarn を選択してインストール
? Which package manager would you ❤️ to use? yarn
とりあえずサーバー立ててみる
$ yarn start:dev
http://localhost:3000/ にアクセスして「Hello World!」って出てればセットアップ完了です!
ディレクトリ説明
作成されたプロジェクトを見てみましょう!
nest.jsではプロジェクト作成時にhello world
を返すapiサンプルが用意されています!
仕組みをざっくり説明すると
controllerでリクエストを受け取り、serviceで用意したデータ(hello world
)を返します、controllerとserviceの紐付けはmoduleで行っているといった感じ
nestjs-prisma-crud
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
...省略
ファイル名 | 説明 |
---|---|
app.controller.spec.ts | テストファイル |
app.controller.ts | APIのリクエスト受け取り |
app.module.ts | 依存関係を定義 |
app.service.ts | 処理メソッド |
main.ts | プロジェクト設定 |
test | E2Eテストコード |
必要なライブラリインストール
別途でインストールが必要なライブラリをインストールしましょう
prismaとfastifyのライブラリを入れます
prismaを使う場合pg
(postgresql)はインストールする必要がないみたい(typeormでは必要だったので)
@nestjs/mapped-types
はこの先に出てくるdtoというファイルにデフォルトで使われる為入れてます!最終的には不要になります
@nestjs/config
は.envを使うためのライブラリです、今回は使わないので入れなくても良いです!
$ yarn add prisma --dev
$ yarn add @prisma/client @nestjs/platform-fastify @nestjs/config @nestjs/mapped-types
ライブラリの設定を行う
prismaとDBのセットアップ
先ほど導入したprismaをセットアップしていきます
init
をするとルートディレクトリにprisma
と.env
が作成されます
今回はlocaldbのpostgresqlを使って設定を行っていきます
$ yarn prisma init
nestjs-prisma-crud/prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
USER、PASSWORD、HOST、PORT、DATABASEを自分の設定に書き換えてください
nestjs-prisma-crud/.env
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE"
fastifyのセットアップ
fastifyを使用する為にmain.tsを修正します
nestjs-prisma-crud/src/main.ts
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
await app.listen(3000);
}
bootstrap();
環境変数(env)のセットアップ
envの使用準備はConfigModuleを以下のように定義すれば
.envファイルを使用する事ができるようになります
import { ConfigModule } from '@nestjs/config';
...
process.env.HOGE
prisma migrateでDBテーブルを作成
apiを作成する前にprismaのマイグレート機能を使ってDBテーブルを作成します
先ほど作成したschema.prismaにモデル定義を行います
schema.prismを使ってマイグレーションも行えるので、
今回はtask
というテーブルを作ってみます
nestjs-prisma-crud/prisma/schema.prisma
model task {
id Int @default(autoincrement()) @id
title String
content String?
}
マイグレーションは以下のコマンドで実行することが可能です
マイグレーションの名前を聞かれるのでinit
とでもつけておきましょう(初回なので)
$ yarn prisma migrate dev --preview-feature
✔ Name of migration … init
The following migration(s) have been created and applied from new schema changes:
migrations/
└─ 20210301135608_init/
└─ migration.sql
prismaフォルダにDB作成に使われたsqlなどが自動生成されます
nestjs-prisma-crud/prisma
├── migrations
│ ├── 20210301135608_init
│ │ └── migration.sql
│ └── migration_lock.toml
└── schema.prisma
DBクライアントから確認するとtaskというテーブルが作成されている事が確認できました
最後に下記のコメントを実行することで、
@prisma/clientからtaskテーブルを取り扱うことができるようになります
$ yarn prisma generate
REST APIでCRUDを作成する
apiの作成準備が整ったのでCRUD APIを作ってみましょう
nest.jsのCRUDジェネレーターを使ってみる
nest.jsには「CRUDジェネレーター」なるものがあるのでこれでAPIの雛形を作っていきます!
nest g resource
で実行し質問形式で雛形が作れるので、
先ほど作成したテーブルに合わせてtask
というモデルでREST APIで作成してみます!
$ nest g resource
? What name would you like to use for this resource (plural, e.g., "users")? task
? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? Yes
作成されるファイル
以下のようなファイルが生成されます
controller
、module
、service
の他にもいくつかファイルができてますね
簡単に説明すると
dtoはパラメータの型定義やバリデーションに使用できます
ちなみにdtoは「Data Transfer Object」の略らしい
entitiesはオブジェクト定義に使用、TypeORMの場合にマイグレーションにも使えます
nestjs-prisma-crud/src/tasks
├── dto
│ ├── create-task.dto.ts
│ └── update-task.dto.ts
├── entities
│ └── task.entity.ts
├── task.controller.spec.ts
├── task.controller.ts
├── task.module.ts
├── task.service.spec.ts
└── task.service.ts
ファイル名 | 説明 |
---|---|
create-task.dto.ts | postで使用されるパラメータの型定義 |
update-task.dto.ts | putで使われるパラメータの型定義 |
task.entity.ts | オブジェクト定義 |
task.controller.ts | APIのリクエスト受け取り |
task.module.ts | 依存関係を定義 |
task.service.spec.ts | テストファイル |
task.service.ts | 処理メソッド |
controllerでリクエスト受け取れるかチェック
controllerをみるとわかるように以下のようなルーティングができているので、
サーバー立ててチェックしてみます
- /task, POST
- /task, GET
- /task/:id, GET
- /task/:id, PUT
- /task/:id, DELETE
$ yarn start:dev
# {/task, GET}にリクエスト
$ curl localhost:3000/task
>> This action returns all
CRUDを作る
リクエストが受け取れるのを確認できたので
APIでDB操作ができるようにしていきます!
まず初めにprisma/clientを使う準備をします
srcディレクトリ内にprisma.service.ts
を作成して下記のコードを追加します
これだけで使用準備OK!
nestjs-prisma-crud/src/prisma.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient
implements OnModuleInit, OnModuleDestroy {
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
}
次にに不要なファイルを消しちゃいましょう
今回はprismaが用意してくれるパラメータの型定義を使用するので、
dto、entitiesは使わないのでファイルごと消しちゃいました!
moduleに依存関係を定義します
providersにPrismaServiceを追加するだけですね!
nestjs-prisma-crud/src/task/task.module.ts
import { Module } from '@nestjs/common';
import { TaskService } from './task.service';
import { TaskController } from './task.controller';
import { PrismaService } from './../prisma.service';
@Module({
controllers: [TaskController],
providers: [TaskService, PrismaService],
})
export class TaskModule {}
controllerを修正します!
serviceからレスポンスを受け取れるように型をつけます
@prisma/client
からtaskの型定義を使っていますが、
これは先ほどtaskモデルをschema.prisma
登録してyarn prisma generate
をしてから使えるようになっています
どんな事ができるかはprisma公式をみてもらえると!
nestjs-prisma-crud/src/task/task.controller.ts
import {
Controller,
Get,
Post,
Body,
Put,
Param,
Delete,
} from '@nestjs/common';
import { TaskService } from './task.service';
import { task, Prisma } from '@prisma/client';
@Controller('task')
export class TaskController {
constructor(private readonly taskService: TaskService) {}
@Post()
async create(@Body() data: Prisma.taskCreateInput): Promise<task> {
return this.taskService.create(data);
}
@Get()
async findAll(): Promise<task[]> {
return this.taskService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: string): Promise<task> {
return this.taskService.findOne(+id);
}
@Put(':id')
async update(
@Param('id') id: string,
@Body() data: Prisma.taskUpdateInput,
): Promise<task> {
return this.taskService.update(+id, data);
}
@Delete(':id')
async remove(@Param('id') id: string): Promise<task> {
return this.taskService.remove(+id);
}
}
最後に実際に処理を行うserviceの方を実装していきます!
実装にはこちらのリポジトリが参考になりました!
nestjs-prisma-crud/src/task/task.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from './../prisma.service';
import { task, Prisma } from '@prisma/client';
@Injectable()
export class TaskService {
constructor(private prisma: PrismaService) {}
async create(data: Prisma.taskCreateInput): Promise<task> {
return this.prisma.task.create({ data });
}
async findAll(): Promise<task[]> {
return this.prisma.task.findMany();
}
async findOne(id: number) {
return this.prisma.task.findUnique({
where: { id: id },
});
}
async update(id: number, data: Prisma.taskUpdateInput): Promise<task> {
return this.prisma.task.update({
where: { id: id },
data,
});
}
async remove(id: number): Promise<task> {
return this.prisma.task.delete({
where: { id: id },
});
}
}
これで実装は以上です!
次は早速作ったAPIを動かしてみます!
APIを動かしてみる
curlでAPIにリクエストを投げてレスポンスを確認してみます!
$ yarn start:dev
- task Post()
$ curl -X POST localhost:3000/task -H 'Content-Type:application/json' -d "{\"title\":\"あいうえお\", \"content\": \"アイウエオ\"}"
- task Get()
$ curl -X GET localhost:3000/task
[
{"id":1,"title":"あいうえお","content":"アイウエオ"},
{"id":2,"title":"かきくけこ","content":"カキクケコ"},
{"id":3,"title":"さしすせそ","content":"サシスセソ"}
]
- task Get(':id')
$ curl -X GET localhost:3000/task/1
{"id":1,"title":"あいうえお","content":"アイウエオ"}
- task Put(':id')
$ curl -X PUT localhost:3000/task/1 -H 'Content-Type:application/json' -d "{\"title\":\"あああああ\", \"content\": \"いいいいい\"}"
{"id":1,"title":"あああああ","content":"いいいいい"}
- task Delete(':id')
$ curl -X DELETE localhost:3000/task/1
{"id":1,"title":"あああああ","content":"いいいいい"}
gitリポジトリ
今回はnest.jsの一部しか使っていませんが、
割と簡単にAPIを作る事ができました!
prismaも導入が楽で、使用方法もシンプルでよかったです!
prismaはgraphQLとの相性も良いらしく、nest.jsでgraphQLの雛形も作れるので、
graphQLで作ってみても良いですね!
今回使ったリポジトリはこちらになります!
Discussion