概要
Vueでgraphqlからクエリなどをしたときに、レスポンスに対してTSの型を定義する。
この型を自前で定義するのは億劫なので、 graphql-codegen
というツールを使ってschemaなどから型を生成する。
一応、公式ドキュメントのVueの例を参考にしてNuxt(CSRのみ)で動作した。
graphqlのクライアントはapollo。
使い方
基本、公式ドキュメントの通りにやればできる。
インストール
For Yarn:
yarn add graphql
yarn add -D typescript ts-node @graphql-codegen/cli
Getting Stertedだとts-nodeが含まれていないが一応いれておく。
プロジェクトのルートに、 codegen.ts
を作る。
今回の自分の場合だと、各参照先が公式通りにできなかったので少し修正した。
- schema: ローカルのschema定義ファイルへのパス(graphqlのURLも可)
- documents: ルート直下の全ディレクトリのvueファイルが対象
- GraphQL documentsを含むパスを指定
- 実際にリクエストを行う
query
,mutation
,subscription
,fragment
が記載されているファイルが対象 - composablesなファイルにも記載している場合は、
.vue
だけだと検知できないので.ts
も含める必要あり
generates: { ‘./gql/’: {省略
- 生成物の出力先を指定する
import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'hoge/fuga/schema.graphql',
documents: ['**/*.vue'],
ignoreNoDocuments: true, // for better experience with the watcher
generates: {
'./gql/': {
preset: 'client',
config: {
useTypeImports: true
}
}
}
}
export default config
リクエストのgraphqlクエリを準備する
公式の例がシンプルでわかりやいので、これをもとに補足する。
allFilmsWithVariablesQuery
のクエリをgraphql-codegenが解析して型を生成してくれる。
個人的には、allFilmsWithVariablesQueryという命名よりも‘Query’なしで allFilmsWithVariables
としたほうが生成された型の命名が良い感じになるので推奨したい。
生成された型は、 {クエリ名}Query
で生成される。suffixにQueryが入るので、自分のコードからは「Query」を入れない。含めるとQueryQueryになる。(オプションで制御できそうな気もするが)
App.vue
<script setup lang="ts">
import { useQuery } from '@vue/apollo-composable'
import { computed } from 'vue'
import FilmItem from './components/FilmItem.vue'
import { graphql } from '../src/gql'
const { result } = useQuery(
graphql(/* GraphQL */ `
query allFilmsWithVariablesQuery($first: Int!) {
allFilms(first: $first) {
edges {
node {
...FilmItem
}
}
}
}
`),
// variables are typed!
{ first: 10 }
)
// `films` is typed!
const films = computed(() => result.value?.allFilms?.edges?.map(e => e?.node!))
</script>
<template>
<ul>
<li v-for="film of films"><FilmItem :film="film" /></li>
</ul>
</template>
型を生成
コマンドを実行する。codegen.tsで指定したパスに諸々の型定義が出力される。
yarn graphql-codegen
—watchをつけると実装しながら型を生成してくれる。
yarn graphql-codegen --watch
生成した型を参照する
生成されたファイルからインポートして型に使うだけ。
useQuery<{ここに指定}>
import type { allFilmsWithVariablesQuery } from "@/gql/graphql”
const { result } = useQuery<allFilmsWithVariablesQuery>(
AppSyncの場合
下記のようにschemaを拡張して、AppSyncのScalar typesに対応する必要があった。(色々とやり方はありそうだった)
const config: CodegenConfig = {
schema: [
"hoge/fuga/schema.graphql",
"gql/aws.gql",
],
# <https://github.com/dotansimha/graphql-code-generator/discussions/4311#discussioncomment-2921796>
scalar AWSTime
scalar AWSDateTime
scalar AWSTimestamp
scalar AWSEmail
scalar AWSJSON
scalar AWSURL
scalar AWSPhone
scalar AWSIPAddress
scalar BigInt
scalar Double
directive @aws_subscribe(mutations: [String!]!) on FIELD_DEFINITION
# Allows transformer libraries to deprecate directive arguments.
directive @deprecated(reason: String!) on INPUT_FIELD_DEFINITION | ENUM
directive @aws_auth(cognito_groups: [String!]!) on FIELD_DEFINITION
directive @aws_api_key on FIELD_DEFINITION | OBJECT
directive @aws_iam on FIELD_DEFINITION | OBJECT
directive @aws_oidc on FIELD_DEFINITION | OBJECT
directive @aws_cognito_user_pools(
cognito_groups: [String!]
) on FIELD_DEFINITION | OBJECT