投稿日:2023年2月18日
Nest.jsでは特定のデコレータをつけたTypeScriptクラスから簡単にGraphQLのAPIを作成することができます。この記事では、作成したGraphQL APIのTypeScript型定義を自動で生成する方法について詳細に解説します。
Nest.jsはTypeScriptを完全にサポートしているサーバーサイドフレームワークです。
このフレームワークは比較的簡単にGraphQLのAPIを構築することができます。そのパッケージでデフォルトでサポートされている機能の中にTypeScript型定義自動生成機能があるのですが、フロントのコードがTypeScriptである場合この機能が非常に効力を発揮します。
この記事ではGraphQL APIのTypeScript型定義自動生成機能について実際のユースケースを交えて解説して行きます。
この記事のコードは以下の環境で確認されました。
ここで説明に使用するサンプルの環境について説明します。
下のようにサーバーサイドのNest.jsアプリケーションと、フロントサイドのNext.jsアプリケーションが、同じディレクトリに配置してあります。
.
├── nest-app
└── next-app
Nest.jsアプリケーションの中にはcatという名前でGraphQL用のサンプルのモジュールが用意しています。
(Next.jsの側の構造は今回はあまり関係ないので一旦省略します)
ではサンプルの説明はここまでにして実際の実装に入っていきましょう!
では早速Nest.jsアプリケーションの設定を修正して、Next.jsアプリケーションのnest-generatedというディレクトリにgraphql.tsというファイル名で、サンプルで用意したGraphQL APIのTypeScript型定義を生成してみましょう。
公式のドキュメントにあるようにApolloDriverConfigのプロパティのdefinitionsに対して必要な情報を渡すことで、Nest.jsのサーバー起動時に自動生成を走らせることができます。
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsModule } from './cats/cats.module';
// 型定義を作成する先を定義
const GQL_TS_TYPE_DIR = '../next-app/nest-generated';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
debug: true,
playground: true,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
sortSchema: true,
definitions: {
path: join(process.cwd(), GQL_TS_TYPE_DIR, 'graphql.ts'), // TypeScriptの型定義ファイルを作成,
},
}),
CatsModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
では開発用サーバーを起動してみます。
$ npm run start:dev
生成されるTypeScript型定義は以下のようなものです。
/*
* -------------------------------------------------------
* THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
* -------------------------------------------------------
*/
/* tslint:disable */
/* eslint-disable */
export interface Cat {
age: number;
name: string;
ownerName?: Nullable<number>;
}
export interface IQuery {
cat(): Cat | Promise<Cat>;
}
type Nullable<T> = T | null;
かなり良い感じですね!
出力は開発環境のみ使用して、プロダクション環境では出力しないようにしたい時など、useFactory()と ConfigModule を使用して使い分けをすると良いかもしれませんね。
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [
ConfigModule.forRoot(),
GraphQLModule.forRootAsync({
driver: ApolloDriver,
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => {
// 環境情報を取得
const nodeEnv = configService.get('NODE_ENV', 'development');
if (nodeEnv === 'development') {
// 出力先を取得
const gqlTsTypeDir = configService.getOrThrow('GQL_TS_TYPE_DIR');
return {
driver: ApolloDriver,
debug: true,
playground: true,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
sortSchema: true,
definitions: {
path: join(process.cwd(), gqlTsTypeDir, 'graphql.ts'), // TypeScriptの型定義ファイルを作成,
},
};
} else {
return {
driver: ApolloDriver,
debug: false,
playground: false,
autoSchemaFile: true,
};
}
},
inject: [ConfigService],
}),
CatsModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}