序章
GraphQL は、スキーマ定義言語とクエリ言語で構成されるAPIのクエリ言語であり、APIコンシューマーは、柔軟なクエリをサポートするために必要なデータのみをフェッチできます。 GraphQLを使用すると、開発者は、iOS、Android、アプリのWebバリアントなど、複数のクライアントのさまざまなニーズに対応しながらAPIを進化させることができます。 さらに、GraphQLスキーマは、APIにある程度の型安全性を追加すると同時に、APIのドキュメントの形式としても機能します。
Prisma は、オープンソースのデータベースツールキットです。 これは、3つの主要なツールで構成されています。
- Prismaクライアント :Node.jsおよびTypeScript用の自動生成されたタイプセーフなクエリビルダー。
- Prisma Migrate :宣言型データモデリングおよび移行システム。
- Prisma Studio :データベース内のデータを表示および編集するためのGUI。
Prismaは、複雑なデータベースワークフロー(スキーマの移行や複雑なSQLクエリの作成など)に時間を費やすのではなく、付加価値機能の実装に集中したいアプリケーション開発者のために、データベースの操作を容易にします。
このチュートリアルでは、GraphQLとPrismaを組み合わせて使用します。これは、それらの責任が互いに補完し合うためです。 GraphQLは、フロントエンドやモバイルアプリなどのクライアントで使用するためのデータへの柔軟なインターフェイスを提供します。GraphQLは特定のデータベースに関連付けられていません。 これは、データが保存されるデータベースとの相互作用を処理するためにPrismaが登場する場所です。
DigitalOceanのAppPlatformは、インフラストラクチャを気にすることなく、クラウドにアプリケーションをデプロイしてデータベースをプロビジョニングするシームレスな方法を提供します。 これにより、クラウドでアプリケーションを実行する際の運用上のオーバーヘッドが削減されます。 特に、毎日のバックアップと自動フェイルオーバーを備えたマネージドPostgreSQLデータベースを作成する機能を備えています。 App Platformには、デプロイメントの合理化をサポートするネイティブNode.jsがあります。
Node.jsを使用して、JavaScriptでブログアプリケーション用のGraphQLAPIを構築します。 最初にApolloServerを使用して、メモリ内のデータ構造に裏打ちされたGraphQLAPIを構築します。 次に、APIをDigitalOceanAppPlatformにデプロイします。 最後に、Prismaを使用してメモリ内ストレージを置き換え、データをPostgreSQLデータベースに永続化して、アプリケーションを再度デプロイします。
チュートリアルの最後に、Node.js GraphQL APIをDigitalOceanにデプロイします。これは、HTTP経由で送信されたGraphQLリクエストを処理し、PostgreSQLデータベースに対してCRUD操作を実行します。
このプロジェクトのコードは、DigitalOceanCommunityリポジトリにあります。
前提条件
このガイドを開始する前に、次のものが必要です。
- GitHubアカウント。
- DigitalOceanアカウント。
- Gitがコンピューターにインストールされています。 チュートリアルオープンソースへの貢献:Git入門に従って、コンピューターにGitをインストールしてセットアップすることができます。
- Node.jsv10以降がコンピューターにインストールされています。 チュートリアルNode.jsをインストールしてローカル開発環境を作成する方法に従って、コンピューターにNode.jsをインストールしてセットアップできます。
- Docker がコンピューターにインストールされています(PostgreSQLデータベースをローカルで実行するため)。
JavaScript 、 Node.js 、GraphQL、およびPostgreSQLの基本的な知識は役に立ちますが、このチュートリアルでは厳密には必要ありません。
ステップ1—Node.jsプロジェクトを作成する
このステップでは、npmを使用してNode.jsプロジェクトをセットアップし、依存関係をインストールします apollo-server
と graphql
.
このプロジェクトは、このチュートリアル全体で構築およびデプロイするGraphQLAPIの基盤になります。
まず、プロジェクトの新しいディレクトリを作成します。
- mkdir prisma-graphql
次に、ディレクトリに移動して、空のnpmプロジェクトを初期化します。
- cd prisma-graphql
- npm init --yes
このコマンドは最小限を作成します package.json
npmプロジェクトの構成ファイルとして使用されるファイル。
次の出力が表示されます。
OutputWrote to /Users/yourusaername/workspace/prisma-graphql/package.json:
{
"name": "prisma-graphql",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
これで、プロジェクトでTypeScriptを構成する準備が整いました。
次のコマンドを実行して、必要な依存関係をインストールします。
- npm install apollo-server graphql --save
これにより、プロジェクトに依存関係として2つのパッケージがインストールされます。
- apollo-server :GraphQLリクエストの解決方法とデータのフェッチ方法を定義するために使用するHTTPライブラリ。
- graphql :GraphQLスキーマを構築するために使用するライブラリです。
プロジェクトを作成し、依存関係をインストールしました。 次のステップでは、GraphQLスキーマを定義します。
ステップ2—GraphQLスキーマとリゾルバーを定義する
このステップでは、GraphQLスキーマと対応するリゾルバーを定義します。 スキーマは、APIが処理できる操作を定義します。 リゾルバーは、メモリ内のデータ構造を使用してこれらのリクエストを処理するためのロジックを定義します。これは、次のステップでデータベースクエリに置き換えます。
まず、という新しいディレクトリを作成します src
ソースファイルが含まれます:
- mkdir src
次に、次のコマンドを実行して、スキーマのファイルを作成します。
- nano src/schema.js
次に、次のコードをファイルに追加します。
const { gql } = require('apollo-server')
const typeDefs = gql`
type Post {
content: String
id: ID!
published: Boolean!
title: String!
}
type Query {
feed: [Post!]!
post(id: ID!): Post
}
type Mutation {
createDraft(content: String, title: String!): Post!
publish(id: ID!): Post
}
`
ここでは、を使用してGraphQLスキーマを定義します gql
タグ付きテンプレート。 スキーマは型定義のコレクションです(したがって、 typeDefs
)APIに対して実行できるクエリの形状を一緒に定義します。 これにより、GraphQLスキーマ文字列がApolloが期待する形式に変換されます。
スキーマには次の3つのタイプがあります。
Post
:ブログアプリの投稿のタイプを定義し、4つのフィールドが含まれ、各フィールドの後にそのタイプが続きます。たとえば、String
.Query
:を定義しますfeed
角括弧とで示されるように複数の投稿を返すクエリpost
単一の引数を受け入れ、単一の引数を返すクエリPost
.Mutation
:を定義しますcreateDraft
ドラフトを作成するためのミューテーションPost
そしてそのpublish
を受け入れる突然変異id
とを返しますPost
.
すべてのGraphQLAPIにはqueryタイプがあり、mutationタイプがある場合とない場合があることに注意してください。 これらのタイプは通常のオブジェクトタイプと同じですが、すべてのGraphQLクエリのエントリポイントを定義するため、特別です。
次に、 posts
への配列 src/schema.js
ファイル、下 typeDefs
変数:
...
const posts = [
{
id: 1,
title: 'Subscribe to GraphQL Weekly for community news ',
content: 'https://graphqlweekly.com/',
published: true,
},
{
id: 2,
title: 'Follow DigitalOcean on Twitter',
content: 'https://twitter.com/digitalocean',
published: true,
},
{
id: 3,
title: 'What is GraphQL?',
content: 'GraphQL is a query language for APIs',
published: false,
},
]
あなたは posts
3つの事前定義された投稿を持つ配列。 それぞれの構造に注意してください post
オブジェクトが一致する Post
スキーマで定義したタイプ。 この配列は、APIによって提供される投稿を保持します。 次のステップでは、データベースとPrisma Clientが導入されたら、アレイを置き換えます。
次に、を定義します resolvers
下のオブジェクト posts
定義した配列:
...
const resolvers = {
Query: {
feed: (parent, args) => {
return posts.filter((post) => post.published)
},
post: (parent, args) => {
return posts.find((post) => post.id === Number(args.id))
},
},
Mutation: {
createDraft: (parent, args) => {
posts.push({
id: posts.length + 1,
title: args.title,
content: args.content,
published: false,
})
return posts[posts.length - 1]
},
publish: (parent, args) => {
const postToPublish = posts.find((post) => post.id === Number(args.id))
postToPublish.published = true
return postToPublish
},
},
Post: {
content: (parent) => parent.content,
id: (parent) => parent.id,
published: (parent) => parent.published,
title: (parent) => parent.title,
},
}
module.exports = {
resolvers,
typeDefs,
}
GraphQLスキーマと同じ構造に従ってリゾルバーを定義します。 スキーマのタイプのすべてのフィールドには、対応するリゾルバー関数があり、その責任は、スキーマ内のそのフィールドのデータを返すことです。 たとえば、 Query.feed()
リゾルバーは、フィルタリングすることにより、公開された投稿を返します posts
配列。
リゾルバー関数は4つの引数を受け取ります。
parent
:親は、リゾルバーチェーン内の前のリゾルバーの戻り値です。 トップレベルのリゾルバーの場合、親はundefined
、以前のリゾルバが呼び出されていないため。 たとえば、feed
クエリ、query.feed()
リゾルバはで呼び出されますparent
の値undefined
そして、のリゾルバーPost
どこで呼ばれますparent
から返されるオブジェクトですfeed
リゾルバ。args
:この引数は、クエリのパラメータを伝達します。たとえば、post
クエリ、受信しますid
フェッチされる投稿の。context
:各リゾルバーが書き込みおよび読み取りを行うことができるリゾルバーチェーンを通過するオブジェクト。これにより、リゾルバーは情報を共有できます。info
:クエリまたはミューテーションのAST表現。 このシリーズのパートIIIで詳細を読むことができます:GraphQLリゾルバーでの情報引数の謎解き。
以来 context
と info
これらのリゾルバでは必要ありません。 parent
と args
定義されています。
完了したら、ファイルを保存して終了します。
注:リゾルバーが、の4つのリゾルバーのように、リゾルバーの名前と同じフィールドを返す場合 Post
、ApolloServerはそれらを自動的に解決します。 これは、これらのリゾルバーを明示的に定義する必要がないことを意味します。
- Post: {
- content: (parent) => parent.content,
- id: (parent) => parent.id,
- published: (parent) => parent.published,
- title: (parent) => parent.title,
- },
最後に、スキーマとリゾルバーをエクスポートして、次のステップでそれらを使用してApolloServerでサーバーをインスタンス化できるようにします。
ステップ3—GraphQLサーバーを作成する
このステップでは、Apollo Serverを使用してGraphQLサーバーを作成し、サーバーが接続を受け入れることができるようにポートにバインドします。
まず、次のコマンドを実行して、サーバー用のファイルを作成します。
- nano src/server.js
次に、次のコードをファイルに追加します。
const { ApolloServer } = require('apollo-server')
const { resolvers, typeDefs } = require('./schema')
const port = process.env.PORT || 8080
new ApolloServer({ resolvers, typeDefs }).listen({ port }, () =>
console.log(`Server ready at: http://localhost:${port}`),
)
ここでは、サーバーをインスタンス化し、前の手順のスキーマとリゾルバーを渡します。
サーバーがバインドするポートは、 PORT
環境変数。設定されていない場合、デフォルトで次のようになります。 8080
. The PORT
環境変数はAppPlatformによって自動的に設定され、サーバーがデプロイされると接続を受け入れることができるようにします。
ファイルを保存して終了します。
GraphQLAPIを実行する準備が整いました。 次のコマンドでサーバーを起動します。
- node src/server.js
次の出力が表示されます。
OutputServer ready at: http://localhost:8080
開始スクリプトをに追加することをお勧めします package.json
サーバーへのエントリポイントが明確になるようにします。 さらに、これにより、AppPlatformはデプロイ後にサーバーを起動できるようになります。
これを行うには、次の行をに追加します "scripts"
のオブジェクト package.json
:
{
"name": "prisma-graphql",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node ./src/server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"apollo-server": "^2.18.2",
"graphql": "^15.3.0"
}
}
終了したら、ファイルを保存して終了します。
これで、次のコマンドを使用してサーバーを起動できます。
- npm start
GraphQL APIをテストするには、出力からURLを開きます。これにより、GraphQLPlaygroundに移動します。
GraphQL Playgroundは、クエリとミューテーションを送信してAPIをテストできるIDEです。
たとえば、 feed
公開された投稿のみを返すクエリ。IDEの左側に次のクエリを入力し、再生ボタンを押してクエリを送信します。
query {
feed {
id
title
content
published
}
}
応答には、のタイトルが表示されます Subscribe to GraphQL Weekly
そのURLと Follow DigitalOcean on Twitter
そのURLで。
テストするには createDraft
ミューテーション、次のミューテーションを入力します。
mutation {
createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
id
title
content
published
}
}
再生ボタンを使用してミューテーションを送信すると、次のメッセージが表示されます。 Deploying a GraphQL API to DigitalOcean
以内 title
応答の一部としてのフィールド。
注:中括弧内のフィールドを追加または削除することで、ミューテーションから返すフィールドを選択できます。 createDraft
. たとえば、 id
と title
次のミューテーションを送信できます。
mutation {
createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
id
title
}
}
これで、GraphQLサーバーが正常に作成およびテストされました。 次のステップでは、プロジェクトのGitHubリポジトリを作成します。
ステップ4—GitHubリポジトリを作成する
このステップでは、プロジェクトのGitHubリポジトリを作成し、変更をプッシュして、GraphQLAPIをGitHubからAppPlatformに自動的にデプロイできるようにします。
からリポジトリを初期化することから始めます prisma-graphql
フォルダ:
- git init
次に、次の2つのコマンドを使用して、コードをリポジトリにコミットします。
- git add src package-lock.json package.json
- git commit -m 'Initial commit'
変更がローカルリポジトリにコミットされたので、GitHubにリポジトリを作成し、変更をプッシュします。
GitHub に移動して、新しいリポジトリを作成します。 一貫性を保つために、リポジトリに prisma-graphql という名前を付けてから、リポジトリの作成をクリックします。
リポジトリが作成されたら、次のコマンドを使用して変更をプッシュします。これには、デフォルトのローカルブランチの名前を次のように変更することも含まれます。 main
:
- git remote add origin git@github.com:your_github_username/prisma-graphql.git
- git branch -M main
- git push --set-upstream origin main
変更を正常にコミットしてGitHubにプッシュしました。 次に、リポジトリをApp Platformに接続し、GraphQLAPIをデプロイします。
ステップ5—AppPlatformへのデプロイ
このステップでは、前のステップで作成したGitHubリポジトリをDigitalOceanに接続し、変更をGitHubにプッシュしたときにGraphQLAPIが自動的にデプロイされるようにAppPlatformを構成します。
まず、アプリプラットフォームに移動し、アプリの起動ボタンをクリックします。
GitHubアカウントをリンクするためのボタンが表示されます。
それをクリックすると、GitHubにリダイレクトされます。
クリックインストールと承認そして、DigitalOceanにリダイレクトされます。
リポジトリを選択してください your_github_username/prisma-graphql
次へをクリックします。
アプリをデプロイするリージョンを選択し、次へをクリックします。
ここで、アプリの構成をカスタマイズできます。 コマンドの実行が npm start
. デフォルトでは、AppPlatformはHTTPポートをに設定します 8080
、これは、GraphQLサーバーをバインドするように構成したのと同じポートです。
次へをクリックすると、プランを選択するように求められます。
Basic を選択し、 Launch BasicAppをクリックします。 アプリページにリダイレクトされ、初期展開の進行状況が表示されます。
ビルドが完了すると、アプリがデプロイされたことを示す通知が届きます。
これで、アプリ名の下のURLでデプロイされたGraphQLAPIにアクセスできます。 それは下になります ondigitalocean.app
サブドメイン。 URLを開くと、チュートリアルのステップ3で行ったのと同じ方法でGraphQLPlaygroundが開きます。
これで、リポジトリがApp Platformに正常に接続され、GraphQLAPIがデプロイされました。 次に、アプリを進化させ、GraphQLAPIのメモリ内データをデータベースに置き換えます。
ステップ6—PostgreSQLでPrismaを設定する
これまでに作成したGraphQLAPIはメモリ内を使用していました posts
データを格納する配列。 これは、サーバーが再起動すると、データへのすべての変更が失われることを意味します。 データが安全に保持されるようにするには、 posts
PostgreSQLデータベースを使用して配列し、Prismaを使用してデータにアクセスします。
このステップでは、Prisma CLIをインストールし、最初のPrismaスキーマを作成し、Dockerを使用してローカルでPostgreSQLをセットアップし、Prismaをそれに接続します。
Prismaスキーマは、Prismaセットアップのメイン構成ファイルであり、データベーススキーマが含まれています。
次のコマンドを使用してPrismaCLIをインストールすることから始めます。
- npm install --save-dev @prisma/cli
Prisma CLIは、データベース移行の実行やPrismaクライアントの生成などのデータベースワークフローを支援します。
次に、Dockerを使用してPostgreSQLデータベースをセットアップします。 次のコマンドを使用して、新しいDockerComposeファイルを作成します。
- nano docker-compose.yml
次に、新しく作成したファイルに次のコードを追加します。
version: '3.8'
services:
postgres:
image: postgres:10.3
restart: always
environment:
- POSTGRES_USER=test-user
- POSTGRES_PASSWORD=test-password
volumes:
- postgres:/var/lib/postgresql/data
ports:
- '5432:5432'
volumes:
postgres:
このDockerCompose構成ファイルは、マシンで公式のPostgreSQLDockerイメージを起動する役割を果たします。 The POSTGRES_USER
と POSTGRES_PASSWORD
環境変数は、スーパーユーザー(管理者権限を持つユーザー)の資格情報を設定します。 また、これらの資格情報を使用してPrismaをデータベースに接続します。 最後に、PostgreSQLがデータを保存するボリュームを定義し、 5432
マシンのポートをDockerコンテナの同じポートに接続します。
ファイルを保存して終了します。
この設定が整ったら、次のコマンドを使用してPostgreSQLデータベースサーバーを起動します。
- docker-compose up -d
次のコマンドを使用して、データベースサーバーが実行されていることを確認できます。
- docker ps
これにより、次のようなものが出力されます。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
198f9431bf73 postgres:10.3 "docker-entrypoint.s…" 45 seconds ago Up 11 seconds 0.0.0.0:5432->5432/tcp prisma-graphql_postgres_1
PostgreSQLコンテナが実行されている状態で、Prismaセットアップを作成できます。 PrismaCLIから次のコマンドを実行します。
- npx prisma init
ベストプラクティスとして、PrismaCLIのすべての呼び出しにはプレフィックスを付ける必要があることに注意してください npx
. これにより、ローカルインストールを使用していることが保証されます。
コマンドを実行した後、PrismaCLIはという新しいフォルダーを作成しました prisma
あなたのプロジェクトで。 次の2つのファイルが含まれています。
schema.prisma
:Prismaプロジェクトのメイン構成ファイル(データモデルを含める)。.env
:データベース接続URLを定義するためのdotenvファイル。
Prismaがデータベースの場所を認識していることを確認するには、 .env
ファイル:
- nano prisma/.env
調整する DATABASE_URL
次のように見える環境変数:
DATABASE_URL="postgresql://test-user:test-password@localhost:5432/my-blog?schema=public"
データベースのクレデンシャルを使用していることに注意してください test-user
と test-password
、DockerComposeファイルで指定されています。 接続URLの形式の詳細については、 Prismadocsにアクセスしてください。
これでPostgreSQLが正常に起動し、Prismaスキーマを使用してPrismaが構成されました。 次のステップでは、ブログのデータモデルを定義し、PrismaMigrateを使用してデータベーススキーマを作成します。
ステップ7—PrismaMigrateを使用したデータモデルの定義
次に、作成したPrismaスキーマファイルでデータモデルを定義します。 次に、このデータモデルは、Prisma Migrateを使用してデータベースにマップされます。これにより、データモデルに対応するテーブルを作成するためのSQLステートメントが生成および送信されます。
ブログを作成しているので、アプリケーションの主なエンティティはユーザーと投稿になります。 このステップでは、 Post
と同様の構造を持つモデル Post
GraphQLスキーマを入力します。 後のステップで、アプリを進化させ、 User
モデル。
注: GraphQL APIは、データベースの抽象化レイヤーと見なすことができます。 GraphQL APIを構築する場合、GraphQLスキーマがデータベーススキーマに非常に似ているのが一般的です。 ただし、抽象化として、2つのスキーマは必ずしも同じ構造である必要はないため、APIを介して公開するデータを制御できます。 これは、一部のデータがAPIレイヤーに対して機密または無関係であると見なされる可能性があるためです。
Prismaは、独自のデータモデリング言語を使用して、アプリケーションデータの形状を定義します。
あなたの schema.prisma
プロジェクトのフォルダからのファイル package.json
位置しています:
- nano prisma/schema.prisma
注:端末から、現在のフォルダを確認できます。 pwd
コマンド。現在の作業ディレクトリを出力します。 さらに、ファイルをリストする ls
コマンドは、ファイルシステムをナビゲートするのに役立ちます。
次のモデル定義を追加します。
...
model Post {
id Int @default(autoincrement()) @id
title String
content String?
published Boolean @default(false)
}
と呼ばれるモデルを定義しています Post
フィールドの数で。 モデルはデータベーステーブルにマップされます。 フィールドは、個々の列を表します。
The id
フィールドには、次のフィールド属性があります。
@default(autoincrement())
:これにより、列の自動インクリメントのデフォルト値が設定されます。@id
:これにより、列がテーブルの主キーとして設定されます。
完了したら、ファイルを保存して終了します。
モデルが配置されたら、PrismaMigrateを使用してデータベースに対応するテーブルを作成できます。 これは、 migrate dev
移行ファイルを作成して実行するコマンド。
ターミナルを再度開き、次のコマンドを実行します。
- npx prisma migrate dev --preview-feature --name "init" --skip-generate
これにより、次のようなものが出力されます。
OutputPostgreSQL database my-blog created at localhost:5432
Prisma Migrate created and applied the following migration(s) from new schema changes:
migrations/
└─ 20201201110111_init/
└─ migration.sql
Everything is now in sync.
このコマンドは、ファイルシステム上に新しい migration を作成し、それをデータベースに対して実行してデータベーススキーマを作成します。 コマンドに提供されるオプションの概要は次のとおりです。
--preview-feature
:PrismaMigrateは現在preview 状態であるため、必須です。--name "init"
:移行の名前を指定します(ファイルシステム上に作成された移行フォルダーに名前を付けるために使用されます)。--skip-generate
:Prismaクライアントの生成をスキップします(これは次のステップで実行されます)。
君の prisma/migrations
これで、ディレクトリにSQL移行ファイルが追加されます。 このアプローチにより、データベーススキーマへの変更を追跡し、本番環境で同じデータベーススキーマを作成できます。
注:すでにPrismaMigrateを使用している場合 my-blog
データベースとの移行の間に矛盾があります prisma/migration
フォルダとデータベーススキーマは、次の出力でデータベースをリセットするように求められます。
Output? We need to reset the PostgreSQL database "my-blog" at "localhost:5432". All data will be lost.
Do you want to continue? › (y/N)
これを解決するには、次のように入力します y
これにより、データベースがリセットされます。 これにより、データベース内のすべてのデータが失われることに注意してください。
これで、データベーススキーマが作成されました。 次のステップでは、Prisma Clientをインストールし、GraphQLリゾルバーで使用します。
ステップ8—GraphQLリゾルバーでのPrismaクライアントの使用
Prisma Clientは、自動生成されたタイプセーフなオブジェクトリレーショナルマッパー(ORM)であり、Node.jsアプリケーションからデータベース内のデータをプログラムで読み書きするために使用できます。 このステップでは、プロジェクトにPrismaClientをインストールします。
ターミナルを再度開き、PrismaClientnpmパッケージをインストールします。
- npm install @prisma/client
注: Prisma Clientは、Prismaスキーマに基づいてコードを生成することにより、豊富なオートコンプリートを提供します。 node_modules
フォルダ。 コードを生成するには、 npx prisma generate
指図。 これは通常、新しい移行を作成して実行した後に行われます。 ただし、最初のインストールでは、これは必要ありません。これは、 postinstall
針。
データベースとGraphQLスキーマが作成され、Prisma Clientがインストールされたら、GraphQLリゾルバーでPrisma Clientを使用して、データベースのデータを読み書きします。 これを行うには、 posts
これまでデータを保持するために使用した配列。
次のファイルを作成することから始めます。
- nano src/db.js
以下を追加します。
const { PrismaClient } = require('@prisma/client')
module.exports = {
prisma: new PrismaClient(),
}
これにより、Prisma Clientがインポートされ、そのインスタンスが作成され、リゾルバーで使用するインスタンスがエクスポートされます。
保存して閉じます src/db.js
ファイル。
次に、をインポートします prisma
インスタンスに src/schema.js
. これを行うには、 src/schema.js
:
- nano src/schema.js
次にインポート prisma
から ./db
ファイルの先頭:
const { prisma } = require('./db')
...
次に、を削除します posts
配列:
-const posts = [
- {
- id: 1,
- title: 'Subscribe to GraphQL Weekly for community news ',
- content: 'https://graphqlweekly.com/',
- published: true,
- },
- {
- id: 2,
- title: 'Follow DigitalOcean on Twitter',
- content: 'https://twitter.com/digitalocean',
- published: true,
- },
- {
- id: 3,
- title: 'What is GraphQL?',
- content: 'GraphQL is a query language for APIs',
- published: false,
- },
-]
今、あなたは更新します Query
データベースから公開された投稿をフェッチするリゾルバー。 を更新します resolvers.Query
次のリゾルバを持つオブジェクト:
...
const resolvers = {
Query: {
feed: (parent, args) => {
return prisma.post.findMany({
where: { published: true },
})
},
post: (parent, args) => {
return prisma.post.findOne({
where: { id: Number(args.id) },
})
},
},
ここでは、2つのPrismaClientクエリを使用しています。
findMany
:投稿を取得しますpublish
フィールドはfalse
.findOne
:単一の投稿を取得しますid
フィールドはid
GraphQL引数。
GraphQL仕様に従って、 ID
タイプは、と同じ方法でシリアル化されます String
. したがって、あなたはに変換します Number
なぜなら id
Prismaスキーマでは int
.
次に、を更新します Mutation
データベース内の投稿を保存および更新するためのリゾルバー。 を更新します resolvers.Mutation
次のリゾルバを持つオブジェクト:
const resolvers = {
...
Mutation: {
createDraft: (parent, args) => {
return prisma.post.create({
data: {
title: args.title,
content: args.content,
},
})
},
publish: (parent, args) => {
return prisma.post.update({
where: {
id: Number(args.id),
},
data: {
published: true,
},
})
},
},
}
2つのPrismaクライアントクエリを使用しています。
create
:作成するPost
記録。update
:の公開フィールドを更新しますPost
そのレコードid
クエリ引数の1つと一致します。
君の schema.js
次のようになります。
const { gql } = require('apollo-server')
const { prisma } = require('./db')
const typeDefs = gql`
type Post {
content: String
id: ID!
published: Boolean!
title: String!
}
type Query {
feed: [Post!]!
post(id: ID!): Post
}
type Mutation {
createDraft(content: String, title: String!): Post!
publish(id: ID!): Post
}
`
const resolvers = {
Query: {
feed: (parent, args) => {
return prisma.post.findMany({
where: { published: true },
})
},
post: (parent, args) => {
return prisma.post.findOne({
where: { id: Number(args.id) },
})
},
},
Mutation: {
createDraft: (parent, args) => {
return prisma.post.create({
data: {
title: args.title,
content: args.content,
},
})
},
publish: (parent, args) => {
return prisma.post.update({
where: {
id: Number(args.id),
},
data: {
published: true,
},
})
},
},
}
module.exports = {
resolvers,
typeDefs,
}
ファイルを保存して閉じます。
Prisma Clientを使用するようにリゾルバーを更新したので、サーバーを起動して、次のコマンドを使用してGraphQLAPIとデータベース間のデータのフローをテストします。
- npm start
繰り返しになりますが、次の出力が表示されます。
OutputServer ready at: http://localhost:8080
出力からのアドレスでGraphQLプレイグラウンドを開き、ステップ3と同じクエリを使用してGraphQLAPIをテストします。
次に、変更をコミットして、変更をAppPlatformにデプロイできるようにします。
コミットを回避するには node_modules
フォルダと prisma/.env
ファイル、作成することから始めます .gitignore
ファイル:
- nano .gitignore
ファイルに以下を追加します。
node_modules
prisma/.env
ファイルを保存して終了します。
次に、次の2つのコマンドを実行して、変更をコミットします。
- git add .
- git commit -m 'Add Prisma'
次に、AppPlatformのアプリにPostgreSQLデータベースを追加します。
ステップ9—AppPlatformでのPostgreSQLデータベースの作成と移行
このステップでは、PostgreSQLデータベースをAppPlatformのアプリに追加します。 次に、Prisma Migrateを使用して移行を実行し、デプロイされたデータベーススキーマがローカルデータベースと一致するようにします。
まず、 App Platformコンソールに移動し、手順5で作成したprisma-graphqlプロジェクトを選択します。
次に、コンポーネントタブに移動します。
+コンポーネントの作成をクリックし、データベースを選択すると、データベースを構成するページが表示されます。
Dev Database を選択し、 Create andAttachをクリックします。
コンポーネントページにリダイレクトされ、データベースを作成するためのプログレスバーが表示されます。
データベースが作成されたら、ローカルマシンからDigitalOcean上の本番データベースに対してデータベース移行を実行します。 移行を実行するには、ホストされているデータベースの接続文字列が必要です。 入手するには、[コンポーネント]タブのdbアイコンをクリックします。
接続の詳細で、ドロップダウンの接続文字列を選択し、データベースのURLをコピーします。これは次の構造になります。
postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require
次に、ターミナルで次のコマンドを実行し、設定したことを確認します DATABASE_URL
コピーしたのと同じURLに:
- DATABASE_URL="postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require" npx prisma migrate deploy --preview-feature
これにより、PrismaMigrateを使用してライブデータベースに対して移行が実行されます。
移行が成功すると、次のメッセージが表示されます。
OutputPostgreSQL database db created at unique_identifier.db.ondigitalocean.com:25060
Prisma Migrate applied the following migration(s):
migrations/
└─ 20201201110111_init/
└─ migration.sql
これで、DigitalOceanの本番データベースが正常に移行されました。これは、Prismaスキーマと一致します。
これで、次のコマンドを使用してGitの変更をプッシュすることでアプリをデプロイできます。
- git push
注:AppPlatformは DATABASE_URL
実行時にアプリケーションで使用できる環境変数。 Prisma Clientは、 env("DATABASE_URL")
の中に datasource
Prismaスキーマのブロック。
これにより、ビルドが自動的にトリガーされます。 App Platformコンソールを開くと、Deployingプログレスバーが表示されます。
展開が成功すると、正常に展開されましたメッセージが表示されます。
これで、デプロイされたGraphQLAPIをデータベースでバックアップしました。 Live App を開くと、GraphQLPlaygroundに移動します。 手順3と同じクエリを使用してGraphQLAPIをテストします。
最後のステップでは、次を追加してGraphQLAPIを進化させます。 User
モデル。
ステップ10—ユーザーモデルの追加
ブログ用のGraphQLAPIには、という名前の単一のエンティティがあります Post
. このステップでは、Prismaスキーマで新しいモデルを定義し、新しいモデルを利用するようにGraphQLスキーマを適応させることにより、APIを進化させます。 紹介します User
1対多の関係を持つモデル Post
モデル。 これにより、投稿の作成者を表し、各ユーザーに複数の投稿を関連付けることができます。 次に、GraphQLスキーマを進化させて、APIを介してユーザーを作成し、投稿をユーザーに関連付けることができるようにします。
まず、Prismaスキーマを開き、以下を追加します。
...
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
posts Post[]
}
Prismaスキーマに以下を追加しました。
- The
User
ユーザーを表すモデル。 - 2つの関係フィールド:
author
とposts
. 関係フィールドは、Prismaレベルでモデル間の接続を定義し、データベースには存在しません。 これらのフィールドは、Prismaクライアントを生成し、Prismaクライアントとの関係にアクセスするために使用されます。 - The
authorId
フィールドは、によって参照されます@relation
属性。 Prismaは、接続するためにデータベースに外部キーを作成しますPost
とUser
.
の作成者フィールドに注意してください Post
モデルはオプションです。 つまり、ユーザーに関連付けられていない投稿を作成できるようになります。
完了したら、ファイルを保存して終了します。
次に、次のコマンドを使用して、移行をローカルで作成して適用します。
- npx prisma migrate dev --preview-feature --name "add-user"
移行が成功すると、次のメッセージが表示されます。
OutputPrisma Migrate created and applied the following migration(s) from new schema changes:
migrations/
└─ 20201201123056_add_user/
└─ migration.sql
✔ Generated Prisma Client to ./node_modules/@prisma/client in 53ms
このコマンドは、新しいテーブルとフィールドを利用できるようにPrismaClientも生成します。
次に、データベーススキーマがローカルデータベースと同じになるように、AppPlatformの本番データベースに対して移行を実行します。 ターミナルで次のコマンドを実行し、設定します DATABASE_URL
App Platformから接続URLへ:
- DATABASE_URL="postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require" npx prisma migrate deploy --preview-feature
あなたは以下を受け取ります:
OutputPrisma Migrate applied the following migration(s):
migrations/
└─ 20201201123056_add_user/
└─ migration.sql
ここで、GraphQLスキーマとリゾルバーを更新して、更新されたデータベーススキーマを利用します。
を開きます src/schema.js
ファイルと更新を追加 typeDefs
次のように:
...
const typeDefs = gql`
type User {
email: String!
id: ID!
name: String
posts: [Post!]!
}
type Post {
content: String
id: ID!
published: Boolean!
title: String!
author: User
}
type Query {
feed: [Post!]!
post(id: ID!): Post
}
type Mutation {
createUser(data: UserCreateInput!): User!
createDraft(authorEmail: String, content: String, title: String!): Post!
publish(id: ID!): Post
}
input UserCreateInput {
email: String!
name: String
posts: [PostCreateWithoutAuthorInput!]
}
input PostCreateWithoutAuthorInput {
content: String
published: Boolean
title: String!
}
`
...
この更新されたコードでは、GraphQLスキーマに次の変更を追加しています。
- The
User
タイプ、の配列を返しますPost
. - The
author
フィールドにPost
タイプ。 - The
createUser
突然変異、それは期待しますUserCreateInput
入力タイプとして。 - The
PostCreateWithoutAuthorInput
で使用される入力タイプUserCreateInput
の一部として投稿を作成するための入力createUser
突然変異。 - The
authorEmail
オプションの引数createDraft
突然変異。
スキーマが更新されたら、スキーマに一致するようにリゾルバーを更新します。
を更新します resolvers
次のようなオブジェクト:
...
const resolvers = {
Query: {
feed: (parent, args) => {
return prisma.post.findMany({
where: { published: true },
})
},
post: (parent, args) => {
return prisma.post.findOne({
where: { id: Number(args.id) },
})
},
},
Mutation: {
createDraft: (parent, args) => {
return prisma.post.create({
data: {
title: args.title,
content: args.content,
published: false,
author: args.authorEmail && {
connect: { email: args.authorEmail },
},
},
})
},
publish: (parent, args) => {
return prisma.post.update({
where: { id: Number(args.id) },
data: {
published: true,
},
})
},
createUser: (parent, args) => {
return prisma.user.create({
data: {
email: args.data.email,
name: args.data.name,
posts: {
create: args.data.posts,
},
},
})
},
},
User: {
posts: (parent, args) => {
return prisma.user
.findOne({
where: { id: parent.id },
})
.posts()
},
},
Post: {
author: (parent, args) => {
return prisma.post
.findOne({
where: { id: parent.id },
})
.author()
},
},
}
リゾルバーへの変更を分解してみましょう。
- The
createDraft
ミューテーションリゾルバは現在、authorEmail
作成されたドラフトと既存のユーザーの間に関係を作成するための引数(渡された場合)。 - 新しい
createUser
ミューテーションリゾルバーは、ネストされた書き込みを使用してユーザーと関連する投稿を作成します。 - The
User.posts
とPost.author
リゾルバは、を解決する方法を定義しますposts
とauthor
フィールドの場合User
またPost
照会されます。 これらは、Prismaの FluentAPIを使用してリレーションをフェッチします。
ファイルを保存して終了します。
サーバーを起動して、GraphQLAPIをテストします。
- npm start
テストすることから始めます createUser
次のGraphQLミューテーションを持つリゾルバー:
mutation {
createUser(data: { email: "natalia@prisma.io", name: "Natalia" }) {
email
id
}
}
これにより、ユーザーが作成されます。
次に、テストします createDraft
次のミューテーションを持つリゾルバー:
mutation {
createDraft(
authorEmail: "natalia@prisma.io"
title: "Deploying a GraphQL API to App Platform"
) {
id
title
content
published
author {
id
name
}
}
}
フェッチできることに注意してください author
クエリの戻り値が Post
. この例では、 Post.author
リゾルバが呼び出されます。
最後に、変更をコミットしてプッシュし、APIをデプロイします。
- git add .
- git commit -m "add user model"
- git push
Prisma Migrateを使用してデータベーススキーマを正常に進化させ、GraphQLAPIで新しいモデルを公開しました。
結論
この記事では、PrismaとGraphQLを使用してGraphQL APIを構築し、それをDigitalOceanのAppPlatformにデプロイしました。 ApolloServerを使用してGraphQLスキーマとリゾルバーを定義しました。 次に、GraphQLリゾルバーでPrisma Clientを使用して、PostgreSQLデータベースのデータを永続化およびクエリしました。
次のステップとして、個々のユーザーをフェッチするクエリと、既存のドラフトをユーザーに接続するミューテーションを使用して、GraphQLAPIをさらに拡張できます。
データベース内のデータの調査に興味がある場合は、 PrismaStudioをチェックしてください。 必ずPrismaドキュメントにアクセスして、Prismaのさまざまな側面について学び、prisma-examplesリポジトリですぐに実行できるサンプルプロジェクトを調べてください。
このプロジェクトのコードは、DigitalOceanCommunityリポジトリにあります。