5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScript + Nexus + Prisma で GraphQL ( for MySQL ) 環境を構築したった

Posted at

はじめに

はじめまして。全然関係ないけど、最近は Vue を裏切って React 書いてます。

さて、前回、TypeORM を使って Node.js の GraphQL 環境を構築しましたが、ぶっちゃけ TypeORM と GraphQL との親和性があまり良くなくて、結局、その後の開発がそこまでドライブしませんでした。
そんな中、今のチームで Node.js で GraphQL の API サーバを新たに構築する必要があり、参考になる既存資産もあったので Nexus + Prisma でやってみました。

以下の記事を大いに参考にさせていただいております。

実際にやってみた

Prisma

Next-generation Node.js and TypeScript ORM

と謳っています。
公式の記載の通り、こちらは ORM ライブラリです。

インストールします。
package.json は事前に準備してください。

$ npm i @prisma/client@2.23

2 系を使っているのは、当初、3 系で構築してみて動かしたらエラったためです 😊😊😊

続いて、最初に必要になるコードを自動生成します。以下を実行。

$ npx prisma init

prisma/ が生成されるので、中に配置されている .envschema.prisma を修正。

.env
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview).
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="mysql://${username}:${password}@${host}:${port}/${db_name}"

続いて、接続の定義と Schema 定義を行います。
以下はサンプルです。

schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Company {
  id       Int       @id @default(autoincrement())
  name     String
  address  String
  accounts Account[]
}

model Account {
  id        Int     @id @default(autoincrement())
  name      String
  email     String  @unique
  companyId Int
  company   Company @relation(fields: [companyId], references: [id])
}

接続設定と Schema のファイルを修正したら migration ファイルを生成。以下コマンドを実行。
この辺は元記事時点とのバージョンの違いからコマンドに差異があります。

$ npx prisma migrate dev --name ${migration_file_name} --create-only

prisma/2021xxxxxxxxxx_${migration_file_name} 的なディレクトリができているので、その中に .mysql ファイルがあることを確認。
以下を実行すると migration が走ります。

$ npx prisma migrate dev
(省略)

✔ Generated Prisma Client (2.30.3) to ./node_modules/@prisma/client in 159ms

最後にこんなログが出力されれば成功です。

ターミナルから MySQL に直接ログインできる方は実際にテーブルを確認してみてください。

次に、↑で定義した Schema 情報から prisma-client の型を生成します。

$ npx prisma generate

Apollo Server

Express で Apollo Server を動かすための設定を行います。

Apollo Server は、ApolloClient を含むすべての GraphQL クライアントと互換性のあるオープンソースの仕様準拠の GraphQL サーバーです。
ちなみに、上記はただ公式の英文を翻訳しただけです。

2 系を使っているのは、当初、3 系で構築してみて動かしたらエラったためです 😊😊😊

$ npm i -D ts-node-dev typescript @types/express
$ npm i express apollo-server-express@2

tsconfig.json を作成。内容はお好みで。

$ touch tsconfig.json

サーバのエントリポイントなどを作成。
この辺は、ほぼ元記事のコードをパクっております。

src/server.ts
import * as express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { createContext } from './context';
import schema from './schema';

const PORT = 4000;

const app = express();
const apollo = new ApolloServer({ schema, context: createContext });

apollo.applyMiddleware({ app });

app.listen({ port: PORT }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${apollo.graphqlPath}`)
);
src/context.ts
import { PrismaClient } from '@prisma/client';
import { Request } from 'apollo-server-express';

const prisma = new PrismaClient();

export interface Context {
  request: Request;
  prisma: PrismaClient;
}

export function createContext(request: Request): Context {
  return {
    request,
    prisma,
  };
}

package.json に以下を追記。

package.json
{
  ...
  "scripts": {
    "dev": "ts-node-dev --no-notify --respawn --transpile-only src/server.ts",
    "build": "tsc -p .",
    "start": "node dist/server.js",
  }
  ...
}

Nexus

Node.js で Type-Safe に GraphQL のスキーマを構築するためのライブラリだそうです。

インストールします。

$ npm i graphql
$ npm i @nexus/schema nexus nexus-plugin-prisma

Schema のコードを追加します。
元記事とは違い、自動生成コードの出力先を src/gen/ 配下に設定してます。

src/schema.ts
import * as path from 'path';
import { makeSchema } from '@nexus/schema';
import { nexusPrisma } from 'nexus-plugin-prisma';
import * as types from './types';

const schema = makeSchema({
  types,
  plugins: [
    nexusPrisma({
      experimentalCRUD: true,
    }),
  ],
  outputs: {
    schema: path.join(__dirname, './gen/graphql/schema.graphql'),
    typegen: path.join(__dirname, './gen/nexus/types.ts'),
  },
});

export default schema;
src/types/index.ts
export * from './models';
export * from './resolvers';
src/types/models/index.ts
// e.g.
export * from './User'
src/types/models/User.ts
import { objectType } from '@nexus/schema';

// e.g.
export const User = objectType({
  name: 'User',
  definition(t) {
    t.int("id")
  },
});
src/types/resolvers/index.ts
export * from './Query';
export * from './Mutation';
src/types/resolvers/Query.ts
import { queryType } from '@nexus/schema';

// e.g.
export const Query = queryType({
  definition(t) {
    t.crud.user();
  },
});
src/types/resolvers/Mutation.ts
import { mutationType } from '@nexus/schema';

// e.g.
export const Mutation = mutationType({
  definition(t) {
    t.crud.createOneUser();
  },
});

package.json に以下を追記。

package.json
{
  ...
  "scripts": {
    "generate:nexus": "ts-node --transpile-only src/schema"
  }
  ...
}

Nexus の型定義を生成します。

$ npm run generate:nexus

GraphQL Playground

GraphQL Playground を実行します。

$ npm run dev

ブラウザからアクセスしてみて、意図通りの Schema などが表示されていれば成功です。

おわりに

TypeORM を使って無理やり GraphQL を構築していた時よりも、Query の頻出パターンを自動で生成できるなどの仕組みがあるので、こっちの方が圧倒的に便利そうな気配がありました。
初期構築も、前回記事の内容よりも少ないので、明らかに導入も簡単です。そして、TypeORM より日本語の参考記事が多い、気がする。

認証系の組み込みなど、実運用レベルのコードをまだ書いてませんが、これから Node.js で GraphQL サーバの構築を始める方は たぶん こっち使った方がいいと思います。

おしまい。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?