サービス
CoddyのNode.jsジャーニー「TypeScriptとNestJS」セクションの一部。レッスン 9/24。
コントローラーがタスク自体を保持しているため、アプリのほかの部分からタスクにアクセスできません。データとロジックはプロバイダーに置きます。プロバイダーとは、Nestが作成し、要求したクラスに渡すクラスです。
@Injectable()
export class BooksService {
private books = [{ title: 'Dune' }];
}
@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}
}@Injectable()はクラスをマークし、モジュールはそれをprovidersに登録します。クラスはコンストラクターで名前を指定してプロバイダーを要求します。これが依存性注入です。引数の前に付けるprivate readonlyはTypeScriptの省略記法で、フィールドthis.booksServiceを作成し、Nestから渡された値を格納します。Nestは引数の型を読み取ります。コンパイラーはデコレーターが付いたクラスの型を保持します。Nestはプロバイダーを登録したモジュールごとにインスタンスを1つ作成し、それを要求するモジュール内のすべてのクラスに同じインスタンスを渡します。データは共有され、テストでは代わりに偽物を渡すこともできます。
このレッスンは、コントローラーがすでにthis.tasksServiceを呼び出しているところから始まります。
チャレンジ
簡単このステップでは、Status Codes and Errors のプロジェクトファイル(src/tasks/tasks.controller.ts など)ではなく、コースで用意された Nest のタスクトラッカープロジェクトを開きます。これまでの作業は、前のレッスンにそのまま残ります。src/tasks/tasks.service.ts を編集する前に、用意されたファイルを読んでください。このコピーには Nest のタスクルートが含まれており、コントローラーはサービスに処理を委譲するよう準備されています。
タスクはコントローラーの中にあるため、アプリのほかの部分からはアクセスできません。タスクを所有するクラスであるサービスに移しましょう。Nest はサービスを一度作成し、サービスを必要とする各クラスに渡します。コントローラーはすでにサービスを呼び出すよう書き換えられています。あなたの作業は、サービスを完成させ、両者をつなぐことです。
src/tasks/tasks.service.tsで、@nestjs/commonの@Injectable()を使って、クラスTasksServiceにマークを付けます。これにより、Nest がクラスを作成して渡せるようになります。- 同じクラスに、メソッド
create(title)を書きます。このメソッドは、次に使える id(this.tasksの中で最大の id より 1 大きい値)、そのタイトル、およびdone: falseを持つタスクを作成します。そのタスクをthis.tasksに追加して返します。コントローラーのPOST /tasksは、リクエストボディから取得したタイトルを渡してこのメソッドを呼び出します。 idが数値であるメソッドremove(id)を書きます。その id のタスクがない場合は、findOneと同様に 404 を返さなければなりません。まずthis.findOne(id)を呼び出してください。このメソッドは例外をスローします。その後、タスクをthis.tasksから削除します。戻り値はありません。src/tasks/tasks.module.tsで、./tasks.serviceからTasksServiceをインポートします。次に、controllersの隣にprovidersリストをモジュールに追加し、その中にTasksServiceを入れます。Nest が作成するのは、モジュールがそこに登録したクラスだけです。src/tasks/tasks.controller.tsで、TasksController内のコメントを、パラメーターを1つ受け取るコンストラクターに置き換えます。パラメーターはprivate readonly tasksService: TasksServiceと書きます。Nest は型TasksServiceを見て、そのサービスを渡します。また、パラメーターの前にあるprivate readonlyは、渡された値を保持するフィールドthis.tasksServiceも作成します。これが、以下のメソッドですでに使われている名前です。
試してみましょう: /tasks に POST { "title": "Buy milk" } を送信します。201 と次の応答が返ります。
{ "id": 4, "title": "Buy milk", "done": false }GET /tasks を送信すると、タスクが4つ返り、最後に Buy milk が表示されます。DELETE /tasks/4 を送信すると、204 が返ります。DELETE /tasks/99 を送信すると、"message": "Task 99 not found" とともに 404 が返ります。
自分で試してみよう
import { NotFoundException } from '@nestjs/common';
export interface Task {
id: number;
title: string;
done: boolean;
createdAt?: string;
}
// このクラスを Nest が注入できるプロバイダーにしてください。
export class TasksService {
private tasks: Task[] = [
{ id: 1, title: 'Write the README', done: true, createdAt: '2026-01-05T09:00:00.000Z' },
{ id: 2, title: 'Fix the login bug', done: false, createdAt: '2026-01-06T14:30:00.000Z' },
{ id: 3, title: 'Plan the sprint', done: false, createdAt: '2026-01-07T08:15:00.000Z' },
];
findAll(done?: string): Task[] {
if (done === undefined) {
return this.tasks;
}
return this.tasks.filter((task) => task.done === (done === 'true'));
}
findOne(id: number): Task {
const task = this.tasks.find((task) => task.id === id);
if (!task) {
throw new NotFoundException(`Task ${id} not found`);
}
return task;
}
// ここに create(title) と remove(id) を実装してください。
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
TypeScriptとNestJSのすべてのレッスン
自分で練習してみよう: Expressプレイグラウンド