既に Apollo Server 3 ベースのバックエンドを稼働中だが、今回新しい環境を作ることになったので、Apollo Server 4 で行うことに!
ライブラリ別相互関係
頭の整理を含め、PostGreSQL や SQLite などの関係データベースを持つバックエンド環境を作る上に必要なライブラリー別の位置付け(?)を考えて見たのが⬇︎です。
- Nexus は GraphQL スキマです。GraphQL Server と Prisma を繋ぎやすくしてくれます。
– GraphQL 用ファイルを自動生成:nexus-typegen.ts
– Prisma 用ファイル自動生成:schema.graphql - Prisma はオブジェクト関係マッピング(Object-relational mapping、ORM) データベース(SQList、PostgreSQLなど)とオブジェクト指向プログラミング言語の間の非互換なデータを変換してくれます。
プロジェクトを作成する
apollo-server-express
を使うと、ポート番号や Endpoint の変更ができます。(任意)
Apollo Server 4からは @apollo/server/express4 の expressMiddleware を使用します。
try🐶everything jacetemp$ mkdir backend && cd backend try🐶everything backend$ npm init -y try🐶everything backend$ npm install @apollo/server express graphql cors body-parser try🐶everything backend$ npm install --save-dev typescript ts-node-dev
tsconfig.json を作成する
// tsconfig.json try🐶everything backend$ cat tsconfig.json { "compilerOptions": { "target": "ES2018", "module": "commonjs", "lib": ["esnext"], "strict": true, "allowJs": true, "rootDir": ".", "outDir": "dist", "sourceMap": true, "moduleResolution": "node", "types": ["node"], "typeRoots": ["./node_modules/@types", "./src/@types"], "esModuleInterop": true, "resolveJsonModule": true, "experimentalDecorators": true, "emitDecoratorMetadata": true } } try🐶everything backend$
scripts コマンドを追加する
try🐶everything backend$ cat package.json { 。。。 "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "ts-node-dev --transpile-only --no-notify src/index.ts", // <-- 追加 "dev:typecheck": "tsc --noEmit --watch", // <-- 追加 "build": "tsc" },
Nexus を設定する
try🐶everything backend$ mkdir src && touch src/schema.ts try🐶everything backend$ cat src/schema.ts import { makeSchema } from "nexus"; import { join } from "path"; export const schema = makeSchema({ types: [], outputs: { // src/generated/* にスキマファイルを保存するように設定(任意) typegen: join(__dirname, "generated", "nexus-typegen.ts"), schema: join(__dirname, "generated", "schema.graphql"), }, }); try🐶everything backend$ try🐶everything backend$ touch src/index.ts import { ApolloServer } from "@apollo/server"; import { expressMiddleware } from "@apollo/server/express4"; import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer"; import express from "express"; import http from "http"; import cors from "cors"; import pkg from "body-parser"; import { schema } from "./schema"; const { json } = pkg; interface MyContext { token?: String; } export async function startApolloServer() { const app = express(); const httpServer = http.createServer(app); const server = new ApolloServer<MyContext>({ schema, plugins: [ApolloServerPluginDrainHttpServer({ httpServer })], }); await server.start(); app.use( "/graphql", cors<cors.CorsRequest>(), json(), expressMiddleware(server, { context: async ({ req }) => ({ token: req.headers.token }), }) ); await new Promise<void>((resolve) => httpServer.listen({ port: 4000 }, resolve) ); console.log(`🚀 Server ready at http://localhost:4000/graphql`); } startApolloServer(); try🐶everything backend$
動作を確認する
try🐶everything backend$ yarn dev yarn run v1.22.19 $ ts-node-dev --transpile-only --no-notify src/index.ts [INFO] 09:33:06 ts-node-dev ver. 2.0.0 (using ts-node ver. 10.9.1, typescript ver. 5.2.2) 🚀 Server ready at http://localhost:4000/graphql
http://localhost:4000/graphql
に接続します。
(⬆︎) Fields
に表示される ok: Boolean!
にチェックを入れて、exampleQuery
ボタンを押すと、"ok": true
と結果が出れば OK です。
Prisma を設定する
PostgreSQL と繋ぎます。
パッケージを設置する
try🐶everything backend$ npm init -y try🐶everything backend$ npm install prisma typescript ts-node @types/node --save-dev
Prismaを初期化する
このコマンドは次の 2 つのことを行います。
schema.prisma
というファイルを含むprisma
という新しいディレクトリを作成します。
このファイルには、データベース接続変数とスキーマ モデルを含むPrisma スキーマ
が含まれています。- プロジェクトのルート ディレクトリに
.env ファイル
を作成します。このファイルは、環境変数 (データベース接続など) を定義するために使用されます。
try🐶everything backend$ npx prisma init ✔ Your Prisma schema was created at prisma/schema.prisma You can now open it in your favorite editor. Next steps: 1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started 2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver or mongodb (Preview). 3. Run prisma db pull to turn your database schema into a Prisma schema. 4. Run prisma generate to generate the Prisma Client. You can then start querying your database. ... try🐶everything backend$
データベースを接続する
DB の設定が必要です。まだの方は ⬇︎⬇︎ 記事で設定できます。
データベースに接続するには、Prisma スキーマのデータソース ブロックの URL フィールドをデータベース接続 URL に設定する必要があります。.env ファイル
内の DATABASE_URL
を、既存のデータベースを指すように設定します。
// prisma/schema.prisma ... datasource db { provider = "postgresql" url = env("DATABASE_URL") } // .env // johndoe:randompassword に実際の所有者とパスワードに書き換えてください。 DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
※ 環境変数がコミットされないように、.gitignore ファイルに .env を追加しておく!
データベース スキマ を作成する
Prisma Migrate
を使用してデータベースにテーブルを作成します。 次の Prisma データ モデルを prisma/schema.prisma
の Prisma スキーマに追加します。
// prisma/schema.prisma ... model Post { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt title String @db.VarChar(255) content String? published Boolean @default(false) author User @relation(fields: [authorId], references: [id]) authorId Int } model Profile { id Int @id @default(autoincrement()) bio String? user User @relation(fields: [userId], references: [id]) userId Int @unique } model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] profile Profile? }
データ モデルをデータベース スキーマにマップするには、prisma merge CLI コマンドを使用する必要があります。( $ npx prisma migrate dev --name init
)
このコマンドは次の 2 つのことを行います。
– この移行用に新しい SQL 移行ファイルを作成します。
– prisma/migrations/実行時刻_init/migraion.sql
– データベースに対して SQL 移行ファイルを実行します。
try🐶everything backend$ npx prisma migrate dev --name init Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Datasource "db": PostgreSQL database "xxxxxx", schema "public" at "localhost:5432" Applying migration `20231013063024_init` The following migration(s) have been created and applied from new schema changes: migrations/ └─ 20231013063024_init/ └─ migration.sql Your database is now in sync with your schema. ✔ Generated Prisma Client (v5.4.2) to ./node_modules/@prisma/client in 47ms try🐶everything backend$
※ prisma-client-js ジェネレーターがスキーマで定義されている場合、@prisma/client がインストールされているかどうかがチェックされ、存在しない場合はインストールされます。
実行結果:Prisma 側
// prisma/migrations/20231013063024_init/migration.sql -- CreateTable CREATE TABLE "Post" ( "id" SERIAL NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, "title" VARCHAR(255) NOT NULL, "content" TEXT, "published" BOOLEAN NOT NULL DEFAULT false, "authorId" INTEGER NOT NULL, CONSTRAINT "Post_pkey" PRIMARY KEY ("id") ); ...
実行結果:PostgreSQL 側
pgAdmin4: Servers > PG-01 > Databases > your-project-db > Schemas > public > Tables > Properties
クエリを作成する
Prisma Client を生成したので、データベース内のデータを読み書きするクエリを作成し、いくつかの基本機能を調べます。src/script.ts
という名前の新しいファイルを作成し、次のコードをそれに追加します。
import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); async function main() { const allUsers = await prisma.user.findMany(); // <-- 全てのユーザを調べる console.log(allUsers); } main() .then(async () => { await prisma.$disconnect(); }) .catch(async (e) => { console.error(e); await prisma.$disconnect(); process.exit(1); });
$ npx ts-node src/script.ts
コマンドを実行しますと、まだ、データがないので、[]
が表示されれば OK です。
try🐶everything backend$ npx ts-node src/script.ts [] try🐶everything backend$
他、データの書き込み や 修正 などの続きはこのリンクを貼りながら、割愛いたします。
以上で、基本的な GraphQL 開発環境が完成しました。
参考文献
Nexus Tutorial // <– Prisma 以外のところまではこれがベスト!
Migrating to Apollo Server 4 // <– apollo-server-express
Prisma: Relational Databases // <– PostgreSQL設定まで!
Prisma Quickstart // <– SQLiteに接続し操作する
コメント