آموزش NestJS برای مبتدیان

به آموزش NestJS برای مبتدیان خوش آمدید. در ادامه این آموزش، شما NestJS را از ابتدا خواهید آموخت، به این شکل که تمام مراحل لازم برای نصب NestJS را طی خواهیم کرد، یک پروژه جدید NestJS را از ابتدا ایجاد می کنیم و یک مثال هم از ابتدا تا انتها پیاده سازی می کنیم.

NestJS یک فریم ورک progressive برای Node.js است که برای ساخت برنامه های سمت سرور کارآمد ، قابل اعتماد و مقیاس پذیر استفاده می شود. این فریم ورک از TypeScript به طور کامل پشتیبانی می کند که در واقع از فریم ورک Express در لایه های زیرین بهره می برد.

NestJS سطح دیگری از انتزاع را روی Node.js و Express معرفی می کند و در ادامه به شما کمک می کند تا کد پایه خود را ساختار دهید. وب سایت این پروژه را می توان در https://nestjs.com یافت:

نصب NestJS

قبل از استفاده از NestJS برای ایجاد back-end برنامه خود، باید اطمینان حاصل کنیم که Nest CLI مختصر شده‌ی (Command Line Interface) بر روی سیستم شما نصب شده است. این کار را می توان با استفاده از Node.js Package Manager یا NPM به روش زیر انجام داد:

$ npm i -g @nestjs/cli

البته باید مطمئن شوید که Node.js و NPM از قبل روی سیستم شما نصب شده است. اگر هنوز چنین نیست، فقط دستورالعمل های https://nodejs.org را دنبال کنید تا Node.js و NPM را در سیستم خود نصب کنید.

پس از نصب Nest CLI ، دستور nest در دسترس خواهد بود. برای شروع یک پروژه NestJS جدید می توانید از این دستور به روش زیر استفاده کنید:

$ nest new my-nestjs-01

با اجرای این دستور یک پوشه جدید my-nestjs-01 در مکان فعلی ایجاد می شود و template پیش فرض پروژه در این پوشه دانلود می شود.

بیایید نگاهی دقیق به ساختار اولیه پروژه بیندازیم.

ساختار پروژه

ساختار اولیه پروژه، از پوشه ها و پرونده های زیر تشکیل شده است:

02.png

مهمترین پوشه پروژه پوشه src است. این مکانی است که می توانید فایل های TypeScript را که داخل آن کد برنامه است، پیدا کنید. بعداً، هنگام اجرای اولین مثال، بیشتر وقت خود را صرف کار در این directory خواهیم کرد.

در داخل پوشه src می توانید پنج فایل را در نصب اولیه پروژه پیدا کنید:

  • main.ts: نقطه ورود به برنامه. با استفاده از روش NestFactory.create() یک نمونه جدید از برنامه Nest ایجاد می شود.
  • app.module.ts: شامل اجرای ماژول root برنامه است.
  • app.controller.ts: شامل پیاده سازی یک controller اولیه از NestJS فقط با یک route است.
  • app.service.ts: شامل پیاده سازی یک سرویس اولیه است.
  • app.controller.spec.ts: فایل test برای controller.

بیایید نگاهی دقیق تر به کد بیندازیم:

در فایل main.ts پیاده سازی پیش فرض زیر را خواهید یافت:


    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';

    async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    await app.listen(3000);
    }
    bootstrap();

این نقطه ورود برنامه است. اول از همه NestFactory از کتابخانه @nestjs/core را import می کنیم. علاوه بر این AppModule از فایل app.module.ts پروژه ما import می شود.

سپس، متد bootstrap به صورت async پیاده سازی شده است.

می بینید که تابع bootstrap به صورت async پیاده سازی شده است. داخل این تابع، NestFactory.create() صدا زده شده است و ماژول root برنامه یعنی AppModule به عنوان آرگومان به آن پاس داده شده است. این یک نمونه برنامه NestJS جدید را با ماژول پیوست ایجاد می کند. برای راه اندازی سرور ، مرحله بعدی فراخوانی تابع listen و گذر از port ای است که وب سرور باید روی آن اجرا شود، به عنوان مثال پورت 3000. از آنجا که تابع listen هنگامی که سرور با موفقیت شروع به کار کرده است، promise بر می گرداند، ما در اینجا از کلمه کلیدی await استفاده می کنیم.

در آخر فایل شامل فراخوانی تابع bootstrap است، تا کد اجرا شود.

در ادامه بیایید نگاهی به نحوه اجرای ماژول root برنامه بیندازیم که می توانید آنرا در داخل فایل app.module.ts پیدا کنید:


    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';

    @Module({
    imports: [],
    controllers: [AppController],
    providers: [AppService],
    })
    export class AppModule {}

برای تعریف کلاس AppModule به عنوان ماژول، از دکوراتورModule استفاده می شود که از کتابخانه @nestjs/common وارد می شود. یک object با سه ویژگی به دکوراتور @Module منتقل می شود. این سه ویژگی عبارتند از:

  • imports
  • controllers
  • providers

همه کنترلرها باید بخشی از AppModule باشند که به عنوان عضوی از آرایه، به خاصیت controllers اختصاص داده می شوند (در حالت اولیه برنامه فقط یک controller وجود دارد که به ماژول root اختصاص داده می شود: AppController).

سرویس هایی که باید در AppModule در دسترس باشند، باید در آرایه ای که به خاصیت providers اختصاص داده شده است لیست شوند.

در مرحله بعدی نگاه دقیق تری به پیاده سازی AppController در app.controller.ts می اندازیم:


    import { Controller, Get } from '@nestjs/common';
    import { AppService } from './app.service';

    @Controller()
    export class AppController {
    constructor(private readonly appService: AppService) {}

    @Get()
    getHello(): string {
        return this.appService.getHello();
    }
    }

این یک اجرای بسیار ساده از controller در NestJS است که فقط از یک مسیر GET تشکیل شده است. برای اینکه یک کلاس را به یک controller تبدیل کنید ، باید دکوریتور @Controller را اضافه کنید. این decorator از کتابخانه @nestjs/common وارد می شود.

یک controller به کلاس service تکیه می کند. در این مثال پیش فرض AppController از سرویسی به نام AppService استفاده می کند. AppService در پرونده app.service.ts در حال اجرا است و بنابراین باید دستور import متناظر با آن در بالا اضافه شود.

با استفاده از مفهوم Dependency Injection و با افزودن پارامتر constructor از نوع خودش،  AppService در AppController وارد می شود.

یک route پیش فرض با پیاده سازی متود getHello اجرا می شود. به منظور  اینکه  درخواست های HTTP GET را کنترل شود ، دکوریتور @Get به این متود اضافه می شود. این متود با استفاده از متود getHello از AppService برای بازیابی داده ها و همزمان برگرداندن آن داده ها به عنوان پاسخ عمل می کند.

بیایید حرکت کنیم و ببینیم داخل app.service.ts چه چیزی وجود دارد:


    import { Injectable } from '@nestjs/common';

    @Injectable()
    export class AppService {
    getHello(): string {
        return 'Hello World!';
    }
    }

این فایل حاوی پیاده سازی کلاس AppService است. برای اینکه AppService به یک کلاس service تبدیل شود (که همانطور که قبلاً در یک controller قابل inject شدن است) باید دکوریتور @Injectable قبل از آن کلاس اضافه شود. باز هم این نوع دکوریتور از پکیج @nestjs/common وارد می شود.

اجرای کلاس service بسیار ساده است و فقط شامل اجرای متود getHello است. این متود فقط بازگرداندن رشته  "Hello World!" است. البته در یک سناریوی واقعی از یک متود برای بازیابی داده ها استفاده می شود، به عنوان مثال از پایگاه داده، یک سرویس وب یا برخی از منابع داده دیگر.

اکنون ، با آگاهی از مهمترین عناصر  سازنده برنامه پیش فرض NestJS، آماده هستیم تا سرور را راه اندازی کنیم و نتیجه را ببینیم.

اجرای برنامه

برای راه اندازی سرور ، کافیست دستور زیر را در folder پروژه اجرا کنید:

$ npm run start

سپس باید خروجی زیر را در command line مشاهده کنید:

03.png

در آخر باید پیام “Nest application successfully started” را ببینید. این پیام به شما اطلاع می دهد که سرور آماده است و می توانید اولین درخواست GET را به سادگی با استفاده از مرورگر و باز کردن URL یعنی http://localhost:3000 ارسال کنید. نتیجه را در تصویر زیر مشاهده می کنید:

04.png

تعجبی نیست: متنی که بازگردانده می شود "hello world!" است. این رشته از متود سرویس getHello بازیابی می شود و سپس به عنوان پاسخ درخواست HTTP GET با استفاده از متود controller مربوطه باز می گردد.

گزینه دیگری برای راه اندازی سرور وجود دارد:

$ npm run start:dev

اگر از start:dev script nodemon برای راه اندازی سرور استفاده شود، به این معنی است که همه فایل های کد شما برای تغییر مانیتور می شوند. با شناسایی تغییرات در source code، سرور به طور خودکار مجدداً راه اندازی می شود.

افزودن endpoint جدید

در مرحله بعدی ما قصد داریم از پروژه جدید NestJS برای افزودن نقطه پایان جدید استفاده کنیم. نقطه پایانی که می خواهیم اضافه کنیم باید درخواست های HTTP GET ،POST و DELETE را بپذیرد و برای مدیریت داده های دوره های آنلاین استفاده شود. برای پوشش دادن این نیازها، نقاط پایانی زیر ایجاد می شود:

  • /courses – پذیرش درخواست های HTTP GET برای بازیابی لیستی از تمام دوره های آنلاین موجود
  • /courses/[courseId] – پذیرش درخواست HTTP GET برای بازیابی دوره آنلاین با ID دوره خاص
  • /courses – پذیرش درخواست های HTTP POST برای افزودن دوره های جدید
  • /courses – درخواست HTTP DELETE برای حذف دوره ها. دوره ای که باید حذف شود باید توسط ID آن مشخص شود که با استفاده از یک پارامتر query به درخواست اضافه می شود

ایجاد یک module جدید

از آنجا که NestJS به ما امکان می دهد کد خود را در ماژول ها سازماندهی کنیم، ایده خوبی است که با ایجاد یک ماژول جدید پیاده سازی را شروع کنیم:

$ nest generate module courses

اجرای این دستو ، افزودن یک فایل جدید به پروژه است: /src/courses/courses.module.ts:

در داخل این فایل می توانید پیاده سازی پیش فرض زیر را از یک ماژول خالی به نام CoursesModule پیدا کنید:


    import { Module } from '@nestjs/common';

    @Module({})
    export class CoursesModule {}

دستور import زیر به طور خودکار به app.module.ts اضافه می شود، بنابراین CoursesModule به برنامه NestJS اضافه می شود:


    import { CoursesModule } from './courses/courses.module';

بعلاوه متوجه خواهید شد که CoursesModule به آرایه ای که به خاصیت import دکوراتور @Module اختصاص داده شده، اضافه می شود:


    @Module({
        imports: [CoursesModule],
        controllers: [AppController],
        providers: [AppService],
    })
    export class AppModule {}

ایجاد یک controller جدید

با استفاده از دستور زیر یک controller جدید به CoursesModule اضافه می کنیم:

$ nest g controller courses

اجرای این دستور خروجی زیر را به شما نشان می دهد:

05.png

در اینجا می توانید ببینید که کدام فایل ها به پروژه اضافه شده اند. پیاده سازی controller اصلی در فایل courses.controller.ts موجود است:


    import { Controller } from '@nestjs/common';
    @Controller('courses')
    export class CoursesController {}

این فقط یک controller خالی است. اکنون می توانیم از این فایل برای افزودن کدی که برای تأمین نیازهای ما لازم است استفاده کنیم.

دوباره ، CoursesController به طور خودکار به CoursesModule اضافه می شود ، همانطور که در زیر می بینید:


    import { Module } from '@nestjs/common';
    import { CoursesController } from './courses.controller';

    @Module({
    controllers: [CoursesController]
    })
    export class CoursesModule {}

Mock Data

خوب ما باید برخی از نمونه های دوره های آموزشی را آماده کنیم که در صورت درخواست کاربر قابل بازگشت باشند:

یک فایل جدید در داخل پوشه src/courses در ساختار پروژه خود ایجاد کنید: courses.mock.ts و محتوای زیر را وارد کنید:


    export const COURSES = [
        { id: 1, title: 'NodeJS - The Complete Guide (incl. MVC, REST APIs, GraphQL)', description: "Master Node JS, build REST APIs with Node.js, GraphQL APIs, add Authentication, use MongoDB, SQL & much more!", author: 'Maximilian Schwarzmüller', url: 'https://codingthesmartway.com/courses/nodejs-complete-guide/' },
        { id: 2, title: 'The Complete Web Developer in 2020: Zero to Mastery', description: "Learn to code and become a Web Developer in 2020 with HTML, CSS, Javascript, React, Node.js, Machine Learning & more!", author: 'Andrei Neagoie', url: 'https://codingthesmartway.com/courses/web-developer-2018/' },
        { id: 3, title: 'Learn and Understand NodeJS', description: "Dive deep under the hood of NodeJS. Learn V8, Express, the MEAN stack, core Javascript concepts, and more.", author: 'Anthony Alicea', url: 'https://codingthesmartway.com/courses/learn-understand-nodejs/' },
    ];

راه اندازی service جدید

دسترسی به داده ها توسط یک service، مدیریت خواهد شد، بنابراین مرحله بعدی ایجاد کلاس service با استفاده مجدد از دستور nest است:

$ nest generate service courses

این دستور یک فایل جدید courses.service.ts به پروژه اضافه می کند و کد زیر را در این فایل قرار می دهد:


    import { Injectable } from '@nestjs/common';

    @Injectable()
    export class CoursesService {}

به منظور ایجاد CoursesService به عنوان بخشی از CoursesModule، سرویس به طور خودکار در فایل courses.module.ts اضافه می شود:


    import { Module } from '@nestjs/common';
    import { CoursesController } from './courses.controller';
    import { CoursesService } from './courses.service';

    @Module({
    controllers: [CoursesController],
    providers: [CoursesService]
    })
    export class CoursesModule {}

بیایید مرحله به مرحله اجرای CoursesService را شروع کنیم. ابتدا باید به آرایه داده های دوره های نمونه موجود در فایل courses.mock.ts دسترسی پیدا کنیم:


    import { Injectable, HttpException } from '@nestjs/common';
    import { COURSES } from './courses.mock';

    @Injectable()
    export class CoursesService {
        courses = COURSES;
    }

گرفتن دوره ها

دو متود سرویس getCourses() و getCourse(courseId) برای بازیابی داده ها اجرا می شوند:


    getCourses(): Promise {
        return new Promise(resolve => {
            resolve(this.courses);
        });
    }

    getCourse(courseId): Promise {
        let id = Number(courseId);
        return new Promise(resolve => {
            const course = this.courses.find(course => course.id === id);
            if (!course) {
                throw new HttpException('Course does not exist', 404)
            }
            resolve(course);
        });
    }

از متود getCourses() برای بازگرداندن لیست کامل دوره ها از طریق Promise استفاده می شود. متود getCourse(courseId) فقط یک دوره واحد را با شناسه خود بازیابی می کند. باز هم نتیجه از طریق Promise بازگردانده می شود. در صورت عدم وجود شناسه ای که از طریق پارامتر courseId به آن متود منتقل می شود، پاسخ HTTP Status Code 404 برمی گردد.

افزودن Course

تود سرویس بعدی که باید اجرا شود، addCourse(course) است. این متود برای افزودن دوره های جدید به آرایه دوره ها استفاده می شود. نوع بازگشتی این متود دوباره یک Promise است که پس از افزودن موفقیت آمیز داده ها resolve می شود:


    addCourse(course): Promise {
        return new Promise(resolve => {
            this.courses.push(course);
            resolve(this.courses);
        });
    }

حذف Course

در نهایت اما مهمترین متود، متود deleteCourse(courseId) برای حذف یک دوره خاص از لیست دوره ها است. پیاده سازی آن را می توان در به صورت زیر مشاهده کرد:


    deleteCourse(courseId): Promise {
        let id = Number(courseId);
        return new Promise(resolve => {
            let index = this.courses.findIndex(course => course.id === id);
            if (index === -1) {
                throw new HttpException('Course does not exist', 404);
            }
            this.courses.splice(index, 1);
            resolve(this.courses);
        });
    }

به روز رسانی CoursesController

اکنون می توان از CoursesService برای بازیابی ، افزودن یا حذف داده های دوره استفاده کرد. این دقیقاً عملکردی است که انتظار می رفت پیاده سازی شود. بیایید با استفاده از CoursesService و کلاس CoursesController  اهداف مورد نیاز را بسازیم:


    import { Controller, Get, Param, Post, Body, Delete, Query } from '@nestjs/common';
    import { CoursesService } from './courses.service';
    import { CreateCourseDto } from './create-course.dto';

    @Controller('courses')
    export class CoursesController {
        constructor(private coursesService: CoursesService) {}

        @Get()
        async getCourses() {
            const courses = await this.coursesService.getCourses();
        }

        @Get(':courseId')
        async getCourse(@Param('courseId') courseId) {
            const course = await this.coursesService.getCourse(courseId);
            return course;
        }

        @Post()
        async addCourse(@Body() createCourseDto: CreateCourseDto) {
            const course = await this.coursesService.addCourse(createCourseDto);
            return course;
        }

        @Delete()
        async deleteCourse(@Query() query) {
            const courses = await this.coursesService.deleteCourse(query.courseId);
            return courses;
        }
    }

 

سعید نصیری
سعید نصیری

من برنامه نویس لاراول، PHP و طراح سایت هستم. برنامه نویسی موبایل و تولید اپلیکیشن های موبایل نیز بخش دیگری از توانایی های فردی من هست. تقریبا ده دوازده سالی تجربه مستمر در زمینه طراحی سایت دارم و نزدیک به یک سال هم میشه که در برنامه نویسی موبایل وارد شده ام.

× در حال پاسخ به: