שירות
חלק מהיחידה TypeScript ו-NestJS במסלול ה-Node.js של Coddy. שיעור 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 קוראת את טיפוס הפרמטר, שהמהדר שומר עבור מחלקות שמסומנות בדקורטור, יוצרת מופע אחד עבור המודול שרושם אותו, ומעבירה את אותו מופע לכל מחלקה במודול שמבקשת אותו. הנתונים משותפים, ובבדיקה אפשר להעביר במקום זאת אובייקט דמה.
השיעור הזה נפתח כשהבקר כבר קורא ל-this.tasksService.
אתגר
קלהשלב הזה פותח את פרויקט מעקב המשימות של Nest שהוכן עבור הקורס, ולא את קובצי הפרויקט שלך מתוך קודי מצב ושגיאות (כולל src/tasks/tasks.controller.ts). העבודה הקודמת שלך נשארת בשיעור משלה. קרא את הקבצים שסופקו לפני עריכת src/tasks/tasks.service.ts. העותק הזה מכיל את נתיבי המשימות של Nest, והבקר מוכן להעביר את הטיפול לשירות.
המשימות נמצאות בתוך הבקר, ולכן שום חלק אחר באפליקציה לא יכול לגשת אליהן. העבר אותן לשירות: מחלקה שמנהלת את המשימות, ש-Nest יוצר פעם אחת ומעביר לכל מחלקה שמבקשת אותה. הבקר כבר שוכתב כדי לקרוא לשירות. עליך להשלים את השירות ולחבר בין השניים.
- ב-
src/tasks/tasks.service.ts, סמן את המחלקהTasksServiceבאמצעות@Injectable(), מתוך@nestjs/common. כך Nest יוכל ליצור אותה ולהעביר אותה הלאה. - באותה מחלקה, כתוב מתודה
create(title). היא יוצרת משימה עם המזהה הפנוי הבא (אחד יותר מהמזהה הגדול ביותר ב-this.tasks), עם הכותרת הזאת ועםdone: false. היא מוסיפה את המשימה ל-this.tasksומחזירה אותה. הבקר שלPOST /tasksקורא לה עם הכותרת מתוך גוף הבקשה. - כתוב מתודה
remove(id), שבהidהוא מספר. אם אין משימה עם המזהה הזה, עליה להשיב 404, כמוfindOne: קרא תחילה ל-this.findOne(id), שזורקת שגיאה. לאחר מכן הסר את המשימה מ-this.tasks. היא לא מחזירה דבר. - ב-
src/tasks/tasks.module.ts, ייבא אתTasksServiceמתוך./tasks.service, ואז הוסף למודול רשימתproviders, לצדcontrollers, והכנס אליה אתTasksService. Nest יוצר רק את המחלקות שהמודול מפרט שם. - ב-
src/tasks/tasks.controller.ts, החלף את ההערה בתוךTasksControllerבבנאי שמקבל פרמטר אחד, הכתוב כך:private readonly tasksService: TasksService. Nest מזהה את הטיפוסTasksServiceומעביר את השירות היחיד שלו. המיליםprivate readonlyלפני פרמטר גם יוצרות שדה,this.tasksService, שמחזיק את מה שהועבר. זהו השם שבו כבר משתמשות המתודות למטה.
נסה זאת: שלח POST עם { "title": "Buy milk" } אל /tasks. תקבל 201 ואת התשובה:
{ "id": 4, "title": "Buy milk", "done": false }שלח GET /tasks: ארבע משימות, כאשר Buy milk מופיעה אחרונה. שלח DELETE /tasks/4: תקבל 204. שלח DELETE /tasks/99: תקבל 404 עם "message": "Task 99 not found".
נסו בעצמכם
import { NotFoundException } from '@nestjs/common';
export interface Task {
id: number;
title: string;
done: boolean;
createdAt?: string;
}
// הפכו את המחלקה הזו ל-provider ש-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 אונליין