Chapter 05無料公開

✅フロントエンドのコードを自動生成する

たった
たった
2021.06.25に更新

このチャプターで使用するライブラリ

  • TypeGraphQL
  • graphql-code-generator

GraphQLではSchemaを共有して、その制約の中でAPIを実行します。そのため、APIを実行するコードは一定のルールを持つことになります。

これを自前で用意せず、自動生成させることで開発効率を高めましょう。

1. バックエンドでGraphQL Schemaを自動生成する

schemaを特定のディレクトリに自動生成するように設定します。

be/src/middleware/buildSchema.ts
import {
  buildSchemaSync,
  BuildSchemaOptions,
} from 'type-graphql'
import { GraphQLSchema } from 'graphql'
import path from 'path'

const buildSchema = async (
  options: Partial<BuildSchemaOptions> = {}
): Promise<GraphQLSchema> => {
  return buildSchemaSync({
    // 指定したディレクトリにSchemaファイルを自動生成してくれる
    emitSchemaFile: `${path.dirname(__dirname)}/../schema/generated/schema.gql`,
    ...options,
  })
}

export default buildSchema

schemaはApolloServerに渡します。

be/src/index.ts
import 'reflect-metadata'
import { ApolloServer } from 'apollo-server-express'
import express from 'express'
import cors from 'cors'

import buildSchema from 'src/middleware/buildSchema'

async function bootstrap() {
  const app = express()
  app.use(cors())

  new ApolloServer({
    schema: await buildSchema(),
  }).applyMiddleware({
    app,
    path: '/',
    cors: false,
  })

  app.listen(4000, () => console.log('Server has started!'))
}

bootstrap()

サーバを立ち上げて.gqlファイルが生成されたことを確認してみましょう。

/docker/dev
$ docker-compose up
# ....
# Server has started!
$ vi ../../be/schema/generated/schema.gql # これでファイルが見られるはず!

schema.gqlはコミット不要なので.gitignoreに指定しておきましょう。

2. フロントエンドでGraphQLを操作するコードを自動生成する

graphql-code-genを設定していきます。
今回はurqlを使用しますが、GraphQL Clientはお好みのものを使ってください。

fe/package.json
"scripts": {
+    "gql-gen": "graphql-codegen --config codegen.yml",
},
...
"devDependencies": {
+    "@graphql-codegen/cli": "^1.20.0",
+    "@graphql-codegen/typed-document-node": "^1.18.2",
+    "@graphql-codegen/typescript": "^1.20.0",
+    "@graphql-codegen/typescript-operations": "^1.17.16",
+    "@graphql-codegen/typescript-urql": "^2.0.3",
+    "@graphql-typed-document-node/core": "^3.1.0",
}
fe/codegen.yml
schema:
  # サーバ側がSchemaファイルを置く場所を読みに行く
  - ../be/schema/generated/schema.gql
  - scalar Upload
documents: ./src/**/*.graphql
generates:
  src/graphql/generated/graphqlOperations.ts:
    plugins:
      - typescript
      - typescript-operations
      - typed-document-node

設定ができたらQueryを書いてみましょう。

fe/src/graphql/query/users.graphql
query users {
  id
  name
  email
  role
}

そしてコードを生成します。

/fe
$ yarn gql-gen
$ vi src/graphql/generated/graphqlOperations.ts # これでファイルが見られるはず!

graphqlOperations.tsはランタイムで必要になるのでコミットしましょう。

Queryを実行するクライアント側のコードはこんな感じ。

fe/src/components/organisms/users/usersName.tsx
import { useMemo } from 'react'
import { useQuery } from 'urql'
import { UsersDocument } 'src/graphql/generated/graphqlOperations.ts'

export const UsersName = () => {
  const [res] = useQuery({
    query: UsersDocument,
  })
  const users = useMemo(() => {
    if(!res.data) return undefined
    if(!res.data.users.length) return undefined
    return res.data.users
  }, [res])
  return {
    {users &&
     users.map((user) => (
       <>
        {user.name}
       </>
     ))
    }
  }
}