Closed10
Fastify, Apollo Server, Pothos で GraphQL サーバー構築手順メモ
実行環境
- Node.js: 20.9.0
- pnpm: 8.10.3
Fastify
Apollo Server
Pothos GraphQL
@as-integrations/fastify
をベースに必要なライブラリをインストール。
$ pnpm install @as-integrations/fastify @apollo/server graphql fastify
apollo-server-integration-fastify
package.json
はこんな感じ(一部省略)
{
"name": "backend",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"run-script": "node --experimental-loader=ts-node/esm",
"dev": "nodemon"
},
"nodemonConfig": {
"exec": "node --env-file=.env --experimental-loader=ts-node/esm/transpile-only ./src/index.ts",
"ext": "ts,js,json",
"watch": [
"src"
]
},
"dependencies": {
"@apollo/server": "4.9.5",
"@as-integrations/fastify": "2.1.1",
"fastify": "4.24.3",
"graphql": "16.8.1"
},
"devDependencies": {
"@types/node": "20.9.0",
"nodemon": "3.0.2",
"ts-node": "10.9.1",
"typescript": "5.2.2"
}
}
example とか参考にしながら src/index.ts
を以下のようにしてみる。
import Fastify from "fastify"
import { ApolloServer, BaseContext } from "@apollo/server"
import fastifyApollo, { fastifyApolloDrainPlugin, fastifyApolloHandler } from '@as-integrations/fastify'
const typeDefs = `
type Query {
hello: String
}
`
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
}
const app = Fastify({
logger: true,
})
const apollo = new ApolloServer<BaseContext>({
typeDefs,
resolvers,
plugins: [fastifyApolloDrainPlugin(app)],
})
await apollo.start()
await app.register(fastifyApollo(apollo))
try {
await app.listen({ port: 65535 })
} catch (err) {
app.log.error(err)
process.exit(1)
}
サーバーを起動し、/graphql
にブラウザでアクセス。
$ pnpm run dev
Apollo Server の GraphQL Explorer が起動したら、Query を投げてレスポンスがかってくることを確認。
その他必要そうなライブラリをインストール。
$ pnpm install @fastify/compress @fastify/cors @fastify/helmet @fastify/rate-limit
dependencies:
+ @fastify/compress 6.5.0
+ @fastify/cors 8.4.1
+ @fastify/helmet 11.1.1
+ @fastify/rate-limit 9.0.1
src/index.ts
に設定。
...
await apollo.start()
await app.register(helmet, {
// false にしないと Explorer が使用できない (Production では true にする)
contentSecurityPolicy: false,
})
await app.register(rateLimit)
await app.register(cors)
await app.register(compress)
...
以下を参考にファイルを分割する。(詳しい設定は後ほど)
./
├── README.md
├── package.json
├── src/
│ ├── context.ts
│ ├── index.ts
│ ├── resolvers.ts
│ └── type-defs.ts
└── tsconfig.json
一旦、build
コマンドを追加する。
package.json
"scripts": {
...
"build": "tsc"
},
tsconfig.json
{
"extends": "tsconfig/backend.json",
"compilerOptions": {
"outDir": "./dist",
"baseUrl": "./src",
"rootDir": "./src"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
build
コマンドを叩くと以下のようになる。
./
├── README.md
├── dist/
│ ├── context.js
│ ├── context.js.map
│ ├── index.js
│ ├── index.js.map
│ ├── resolvers.js
│ ├── resolvers.js.map
│ ├── type-defs.js
│ └── type-defs.js.map
├── package.json
├── src/
│ ├── context.ts
│ ├── index.ts
│ ├── resolvers.ts
│ └── type-defs.ts
├── tsconfig.json
└── tsconfig.tsbuildinfo
Pothos GraphQL
をインストールする。
$ pnpm install @pothos/core
dependencies:
+ @pothos/core 3.41.0
公式の Hello, World と examples を基に初期セットアップ。
./
├── ...
├── src/
│ ├── graphql/
│ │ ├── builder.ts
│ │ ├── context.ts
│ │ ├── schema.ts
│ │ └── server.ts
│ └── index.ts
└── tsconfig.json
graphql/builder.ts
import SchemaBuilder from '@pothos/core'
export const builder = new SchemaBuilder({})
graphql/schema.ts
import { builder } from './builder.js'
builder.queryType({
fields: (t) => ({
hello: t.string({
args: {
name: t.arg.string(),
},
resolve: (parent, { name }) => `hello, ${name || 'World'}`,
}),
}),
})
export const schema = builder.toSchema()
graphql/server.ts
import { ApolloServer } from '@apollo/server'
import { fastifyApolloDrainPlugin } from '@as-integrations/fastify'
import { schema } from './schema.js'
import type { Context } from './context'
import type { FastifyInstance } from 'fastify'
export const createApolloServer = ({ app }: { app: FastifyInstance }) => {
return new ApolloServer<Context>({
schema,
plugins: [fastifyApolloDrainPlugin(app)],
})
}
index.ts
...
import { createApolloServer } from './graphql/server.js'
const apollo = createApolloServer({ app })
await apollo.start()
...
引数を含めたレスポンスが返ってくることを確認。
GraphQL Code Generator
で GraphQL スキーマと TypeScript の型を出力する。
まず、必要なライブラリをインストールする。
$ pnpm install @graphql-codegen/cli @graphql-codegen/client-preset -D
codegen.ts
を作成する。(パスは任意のパス)
codegen.ts
import { printSchema } from 'graphql'
import { schema } from './schema/index.js'
import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: printSchema(schema),
generates: {
'path/to/file.graphql': {
plugins: ['schema-ast'],
},
'path/to/': {
preset: 'client',
plugins: [],
},
},
}
export default config
現在のディレクトリ構成
./
├── ...
├── package.json
├── src/
│ ├── graphql/
│ │ ├── codegen.ts
│ │ ├── context.ts
│ │ ├── data.ts
│ │ ├── schema/
│ │ │ ├── builder.ts
│ │ │ ├── comment.ts
│ │ │ ├── index.ts
│ │ │ ├── post.ts
│ │ │ └── user.ts
│ │ └── server.ts
│ └── index.ts
└── tsconfig.json
package.json
に generate
コマンドを追加。
package.json
{
...
"scripts": {
...
"generate": "graphql-codegen --config ./src/graphql/codegen.ts"
},
...
}
generate
コマンドを叩き、ts ファイルと graphql スキーマが出力されることを確認。
./path/to/
├── fragment-masking.ts
├── gql.ts
├── graphql.ts
├── index.ts
└── schema.graphql
このスクラップは2023/12/25にクローズされました