Apollo ServerGraphQLmacOSNexusPostgreSQLPrismaReact Native

【ReactNative】GraphQL Backend 構築 ❶ 〜Apollo Server4・Nexus・Prisma・PostgreSQL〜

apollo-server-nexus-02 Apollo Server
スポンサーリンク

既に Apollo Server 3 ベースのバックエンドを稼働中だが、今回新しい環境を作ることになったので、Apollo Server 4 で行うことに!

ライブラリ別相互関係

頭の整理を含め、PostGreSQL や SQLite などの関係データベースを持つバックエンド環境を作る上に必要なライブラリー別の位置付け(?)を考えて見たのが⬇︎です。

apollo-server-nexus-02
  • 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 に接続します。

apollo-server-nexus-01

(⬆︎) 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

apollo-server-nexus-01

クエリを作成する

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に接続し操作する

コメント

タイトルとURLをコピーしました