Open2
NestJS
NestJSの基本要素
NestJSでコアになるもの
- Module
- Controller(Resolver)
- Service
モジュール
- ResolverやServiceなどをまとめ、アプリケーションで利用できるようにNestJSへ登録をする
- モジュール内部で必要となる外部モジュールのインポートやモジュール内から外部へのエクスポート
- 1つのルートモジュールが必ず必要になる
- @Module()デコレータをつける、プロパティをデコレータ内で定義
リゾルバーの役割
- GraphQL APIがどのような処理を行うかを定義
- データの取得はQuery、それ以外はMutation
- GraphQLスキーマに定義されたデータを返却する
- イメージとしてはREST APIのControllerのようなものに相当
- @Resolver()デコレータを付与する
- 実現したい内容の処理をメソッドとして定義する
サービスの役割
- アプリケーション固有のビジネスロジックを定義する
- リゾルバーから呼び出すことでユースケースを実現する
リゾルばにビジネスロジックを書いてもプログラムは動作するが拡張性などを考えるとサービスに書く方が良い - サービスの定義には@Injectable()デコレータをつける
DI(Dependency Injection)
- 依存性注入
- 依存関係のあるオブジェクトを外部から渡す
- TaskResolver → TaskServiceに依存している
ソースコード例
@Resolver()
export class TaskResolver {
@Query(() => [Task])
getTasks(): Task[] {
const taskService = new TaskService();
return taskService.getTasks();
}
}
この方法だとサービスの依存度を高めてしまう。
例えば本番環境では 下記だが
const taskService = new TaskService();
テスト環境では設定が異なり下記を使うケースがあるとした場合。
const testTaskService = new testTaskService();
Resolver側で呼び出すものをテストの度にソースを変更しなければならないため、ミスによるバグなどもおこりうるし、美しくない。
なのでそれを解決する方法として一般的によく使用される方法がDIであり、service = new TaskService();のインスタンス化はTaskResolverクラスの外で行って外部から渡し、Resolverクラスのコンストラクタで受け取るという形式だ。
NestJSでGraphQLを扱う方法
スキーマファースト
- GraphQL定義スキーマファイルを事前に定義する
- GraphQLスキーマからTypeScriptのコードを生成
- バックエンド、フロントエンドともに同じGraphQLスキーマを参照
- バックエンド、フロントエンド共有の資産にすることができる・特定の言語フレームワークに依存しない
GraphQLスキーマのバージョン管理が煩雑、スキーマ定義言語の文法制約が多い、GraphQLスキーマについての理解が必要になる
コードファースト
- GraphQLスキーマファイルは事前に作成しない
- TypeScriptのコードに特定のデコレーターを付与し、GraphQLスキーマを自動生成
- フロントエンドはバックエンドによって生成されたスキーマを参照
- 比較的小規模なものに向いている
- コードとスキーマを常に一致させることができる
- IDEの強力なサポートを受けられる
- GraphQLの知識があまり必要なく、TypeScriptがかければいい
- スキーマがバックエンドの資産になる
- 特定の言語、フレームワークに依存する