3. Prisma Clientを使ってREST APIの作成 Prisma 入門ワークショップ(2021)
ゴール
このレッスンの目標は、Prisma Clientについて学んだばかりの知識を使って、Expressを使ってREST APIのいくつかのルートを実装することです。
レッスン
0. Prisma 入門ワークショップ(2021)
1. Prismaのセットアップ
2. Prisma Clientを使ってみる
3. Prisma Clientを使ってREST APIの作成←ここ
4. Prisma Clientを使ってGraphQL APIの作成
リソース
Prismaとは?
Node.js & TypeScript向けの完璧なORM
英語のドキュメント
https://www.notion.so/A-Practical-Introduction-to-Prisma-2021-ccf00a066ef4432caeb03da179e38302
Zoom ウェビナー
GitHub。
https://github.com/nikolasburk/prisma-workshop
セットアップ
レッスン1で設定したのと同じ prisma-workshop
プロジェクトで作業を続けることができます。ただし、このレッスンのスターターは、クローンしたレポの rest-api
ブランチにあります。
そのブランチに切り替える前に、プロジェクトの現在の状態をコミットする必要があります。簡単にするために、stash
コマンドを使ってこれを行うことができます。
git stash
このコマンドを実行したら、rest-api
ブランチに切り替えて、現在の migrations
ディレクトリと dev.db
ファイルを削除することができます。
git checkout rest-api
rm -rf prisma/migrations
rm prisma/dev.db
次に、npmの依存関係を一掃し、package.json
にある新しい依存関係を考慮して再インストールします。
rm -rf node_modules
npm install
ここで使用するデータモデルは、先ほど作成したものと非常によく似ています。ただ、Post
モデルにいくつかのフィールドを追加して拡張しています。
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
content String?
published Boolean @default(false)
viewCount Int @default(0)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
Prismaのセットアップを最初からやり直すので、データベースとそのテーブルを再作成する必要があります。以下のコマンドを実行して、これを行います。
npx prisma migrate dev --name init
最後に、prisma/seed.ts
ファイルで指定されたサンプルデータをデータベースにシードします。このseedスクリプトは、以下のコマンドで実行できます。
npx prisma db seed --preview-feature
以上で、タスクの準備が整いました。
タスク
このレッスンのタスクは、TODO
と書かれたsrc/index.ts
ファイルの中にあります。目標は、各REST APIルートに正しいPrismaクライアントのクエリを挿入することです。
これはAPI設計のレッスンではありませんので、実際のアプリケーションでのAPI操作の設計については、より慎重に考える必要があることに注意してください。
VS Codeを使用している場合は、REST Clientエクステンションをインストールし、test.httpで提供されているHTTPコールを使用して実装をテストすることができます。
VS Code REST Clientエクステンションのクイックデモを見る
GET /users
すべてのユーザーを取得します。
答え
app.get("/users", async (req, res) => {
const result = await prisma.user.findMany()
res.json(result)
});
POST /signup
新しいユーザーを作成します。
答え
app.post(`/signup`, async (req, res) => {
const { name, email } = req.body;
const result = await prisma.user.create({
data: {
name,
email
}
})
res.json(result)
});
POST /post
新しいPostを作成します。
答え
app.post(`/post`, async (req, res) => {
const { title, content, authorEmail } = req.body;
const result = await prisma.post.create({
data: {
title,
content,
author: {
connect: {
email: authorEmail
}
}
}
})
res.json(result)
});
PUT /post/:id/views
Postのビュー数を1増やします。
答え
app.put("/post/:id/views", async (req, res) => {
const { id } = req.params;
const result = await prisma.post.update({
where: {
id: Number(id),
},
data: {
viewCount: {
increment: 1,
},
},
});
res.json(result);
});
PUT /publish/:id
Postを公開します。
答え
app.put("/publish/:id", async (req, res) => {
const { id } = req.params;
const result = await prisma.post.update({
where: { id: Number(id) },
data: {
published: true,
},
});
res.json(result);
});
GET /user/:id/drafts
特定のユーザーの未公開のPostを取得します。
答え
app.get("/user/:id/drafts", async (req, res) => {
const { id } = req.params;
const result = await prisma.user.findUnique({
where: { id: Number(id) },
}).posts({
where: {
published: false
}
})
res.json(result)
});
GET /post/:id
指定したIDと一致するPostを取得します。
答え
app.get(`/post/:id`, async (req, res) => {
const { id } = req.params;
const result = await prisma.post.findUnique({
where: { id: Number(id) },
});
res.json(result);
});
GET /feed?searchString=<searchString>&skip=<skip>&take=<take>
公開されているすべてのPostを取得し、検索文字列がタイトルやコンテンツに含まれているかどうかをチェックして、ページネーションやフィルタリングを行います。
答え
app.get("/feed", async (req, res) => {
const { searchString, skip, take } = req.query;
const or = searchString ? {
OR: [
{ title: { contains: searchString as string } },
{ content: { contains: searchString as string } },
],
} : {}
const result = await prisma.post.findMany({
where: {
published: true,
...or
},
skip: Number(skip) || undefined,
take: Number(take) || undefined,
});
res.json(result);
});
Discussion