4. Prisma Clientを使ってGraphQL APIの作成 Prisma 入門ワークショップ(2021)
ゴール
このレッスンの目的は、Prisma Clientについて学んだばかりの知識を使って、Apollo Serverを使ってGraphQL 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
プロジェクトで作業を続けることができます。ただし、このレッスンのスターターは、クローンしたレポの graphql-api
ブランチにあります。
そのブランチに切り替える前に、プロジェクトの現在の状態をコミットする必要があります。簡単にするために、stash
コマンドを使ってこれを行うことができます。
git stash
このコマンドを実行したら、graphql-api
ブランチに切り替えて、現在の migrations
ディレクトリと dev.db
ファイルを削除することができます。
git checkout graphql-api
rm -rf prisma/migrations
rm prisma/dev.db
次に、npmの依存関係を一掃し、package.json
にある新しい依存関係を考慮して再インストールします。
rm -rf node_modules
npm install
ここで使用するデータモデルは、先ほどのREST APIのレッスンで使用したものと似ています。
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
ファイルの中にあります。目標は、各GraphQLリゾルバに対して、適切なPrisma Clientのクエリを挿入することです。
サーバーを起動し、http://localhost:4000
にあるGraphQL Playgroundを開くことで、自分の実装をテストすることができます。
Query.allUsers: [User!]!
すべてのユーザーを取得します。
答え
allUsers: (_parent, _args, context: Context) => {
return context.prisma.user.findMany()
},
GraphQLのサンプルクエリ
{
allUsers {
id
name
email
posts {
id
title
}
}
}
Query.postById(id: Int!): Post
idでPostを取得する。
答え
postById: (_parent, args: { id: number }, context: Context) => {
return context.prisma.post.findUnique({
where: { id: args.id }
})
},
GraphQLのサンプルクエリ
{
postById(id: 1) {
id
title
content
published
viewCount
author {
id
name
email
}
}
}
Query.feed(searchString: String, skip: Int, take: Int): [Post!]!
公開されているすべての投稿を取得し、検索文字列がタイトルやコンテンツに含まれているかどうかをチェックして、ページ分割やフィルタリングを行います。
答え
feed: (
_parent,
args: {
searchString: string | undefined;
skip: number | undefined;
take: number | undefined;
},
context: Context
) => {
const or = args.searchString
? {
OR: [
{ title: { contains: args.searchString as string } },
{ content: { contains: args.searchString as string } },
],
}
: {};
return context.prisma.post.findMany({
where: {
published: true,
...or,
},
skip: Number(args.skip) || undefined,
take: Number(args.take) || undefined,
});
},
GraphQLのサンプルクエリ
{
feed {
id
title
content
published
viewCount
author {
id
name
email
}
}
}
Query.draftsByUser(id: Int!): [Post]
特定のユーザーの未公開のPostを取得します。
答え
draftsByUser: (_parent, args: { id: number }, context: Context) => {
return context.prisma.user.findUnique({
where: { id: args.id }
}).posts({
where: {
published: false
}
})
},
GraphQLのサンプルクエリ
{
draftsByUser(id: 3) {
id
title
content
published
viewCount
author {
id
name
email
}
}
}
Mutation.signupUser(name: String, email: String!): User!
新しいユーザーを作成します。
答え
signupUser: (
_parent,
args: { name: string | undefined; email: string },
context: Context
) => {
return context.prisma.user.create({
data: {
name: args.name,
email: args.email
}
})
},
GraphQLのサンプルクエリ
mutation {
signupUser(
name: "Nikolas"
email: "burk@prisma.io"
) {
id
posts {
id
}
}
}
Mutation.createDraft(title: String!, content: String, authorEmail: String): Post
新しいPostを作成します。
答え
createDraft: (
_parent,
args: { title: string; content: string | undefined; authorEmail: string },
context: Context
) => {
return context.prisma.post.create({
data: {
title: args.title,
content: args.content,
author: {
connect: {
email: args.authorEmail
}
}
}
})
},
GraphQLのサンプルミューテーション
mutation {
createDraft(
title: "Hello World"
authorEmail: "burk@prisma.io"
) {
id
published
viewCount
author {
id
email
name
}
}
}
Mutation.incrementPostViewCount(id: Int!): Post
投稿の表示回数を1回増やすことができます。
答え
incrementPostViewCount: (
_parent,
args: { id: number },
context: Context
) => {
return context.prisma.post.update({
where: { id: args.id },
data: {
viewCount: {
increment: 1
}
}
})
},
GraphQLのサンプルミューテーション
mutation {
incrementPostViewCount(id: 1) {
id
viewCount
}
}
Mutation.deletePost(id: Int!): Post
Postを削除します。
答え
deletePost: (_parent, args: { id: number }, context: Context) => {
return context.prisma.post.delete({
where: { id: args.id }
})
},
GraphQLのサンプルミューテーション
mutation {
deletePost(id: 1) {
id
}
}
User.posts: [Post!]!
指定したユーザーのPostを返します。
答え
User: {
posts: (parent, _args, context: Context) => {
return context.prisma.user.findUnique({
where: { id: parent.id }
}).posts()
},
},
Post.author: User
指定されたPostのAuthorを返します。
答え
Post: {
author: (parent, _args, context: Context) => {
return context.prisma.post.findUnique({
where: { id: parent.id }
}).author()
},
},
Discussion