برای توسعه دهندگان بسیار مهم است که هنگام انتخاب چارچوبی برای پروژه های خود تصمیمی آگاهانه بگیرند. NestJS و Express.js دو مورد از محبوب ترین فریمورک ها در اکوسیستم Node.js برای ساخت برنامه های کاربردی در مقیاس بزرگ هستند. این مقاله NestJS و Express.js را بر اساس ویژگیها، معماری، پشتیبانی جامعه و موارد دیگر مقایسه میکند. مؤلفههای اصلی آنها را بررسی میکند و بینشهایی در مورد موارد استفاده ایدهآل آنها ارائه میکند، و همچنین دستورالعملهایی برای مهاجرت از Express.js به NestJS ارائه میدهد.
NestJS چیست؟
NestJS یک چارچوب Node.js برای ساخت برنامه های سمت سرور است. این فریمورک بر اساس TypeScript و JavaScript است. این چارچوب از Angular الهام گرفته شده است، بنابراین بیشتر مواردی که در Angular پیدا میکنید را میتوانید در Nest نیز پیدا کنید، از جمله providers، میدلور ها، مؤلفهها و سرویس ها. به جرات می توان گفت Nest را می توان به راحتی توسط توسعه دهندگان Angular برای هر نوع پروژه ای یاد گرفت.
Nest به طور پیش فرض از چارچوب Express HTTP استفاده می کند. با این حال، Nest یک پلتفرم آگنوستیک است، به این معنی که می تواند با هر چارچوب HTTP Node کار کند. به عنوان مثال، می توان آن را به صورت اختیاری برای استفاده از Fastify پیکربندی کرد، که می تواند چارچوب Node را بهبود بخشد.
یکی از نکات جالب در مورد NestJS این است که هر چیزی که در Express پشتیبانی می شود (یعنی توابع Express) در Nest نیز پشتیبانی می شود.
اجزای اصلی NestJS
اجازه دهید برخی از اجزای اصلی NestJS را مرور کنیم.
ماژول کلاسی است که با ()@Module
دکراتور نویسی شده است. Nest از متادیتا ارائه شده توسط دکراتور ()Module@
برای سازماندهی ساختار برنامه استفاده می کند.
هر برنامه NestJS حاوی حداقل یک ماژول است که به عنوان ماژول ریشه شناخته می شود. Nest از ماژول ریشه به عنوان نقطه شروع برای حل ساختار و روابط برنامه استفاده می کند. ماژول های پویا یکی از ویژگی های قدرتمند سیستم ماژول Nest هستند. این ویژگی به شما اجازه می دهد تا به راحتی ماژول های قابل تنظیمی ایجاد کنید که می توانند providers را به صورت پویا ثبت و پیکربندی کنند. providers بسیار مهم هستند، زیرا Nest به شدت به آنها برای ایجاد روابط بین اشیاء مختلف متکی است. providers را می توان به عنوان وابستگی تزریق کرد.
کلاس هایی مانند سرویس، ریپزوتوری و helpers را می توان به عنوان providers در نظر گرفت. به سادگی افزودن دکوراتور ()Injectable@
از Nest، وضوح را کنترل می کند و مدیریت وابستگی را بسیار ساده می کند.
هنگامی که یک درخواست HTTP دریافت می شود، مکانیسم مسیریابی آن را به کنترلر صحیح در NestJS هدایت می کند. کنترلرها درخواست های دریافتی را مدیریت می کنند و به سمت کلاینت برنامه پاسخ می دهند.
نحوه نصب NestJS
Nest دارای یک CLI عالی است که ساخت یک برنامه Nest را آسان می کند.
در ترمینال یا command prompt خود، عبارت زیر را تایپ کنید:
npm i -g @nestjs/cli
بیایید از دستور cd برای تغییر به دایرکتوری که می خواهیم برنامه خود را بسازیم استفاده کنیم. دستورات زیر را اجرا کنید:
nest new nest-blog-api
cd nest-blog-api
npm run start:dev
در هر مرورگری به http://localhost:3000
بروید. شما باید یک پیام "Hello World" را ببینید.
ویژگی های NestJS
کار با Node و Express برای ساختن یک اپلیکیشن کوچک و سبک که در آن کد به راحتی قابل خواندن باشد، عالی است. با این حال، هنگامی که همه چیز شروع به پیچیده شدن می کند و ویژگی های بیشتری را به برنامه خود اضافه می کنید، کد شما کمی آشفته تر و مدیریت آن سخت تر می شود.
این جایی است که NestJS وارد میشود. Nest میتواند برنامه شما را در ماژولهای مستقل سازماندهی کند که هر کدام مسئولیت خاص خود را دارند. یک ماژول میتواند شامل کنترلر و سرویسهای مرتبط باشد و آنها را نسبتاً از بقیه برنامههای شما جدا نگه دارد.
Nest از تزریق وابستگی نیز پشتیبانی می کند. استفاده از تزریق وابستگی به این معنی است که شما نیازی به وابستگی سخت به چیزهایی مانند مؤلفهها، سرویسها و میدلور درون کد خود ندارید.
فیلترهای استثنایی یکی دیگر از ویژگی های جالب Nest است. همه برنامه ها هر از گاهی با استثناهایی مواجه می شوند. نحوه برخورد با استثناها مهم است، و Nest به راحتی همه این موارد را برای شما مرتب می کند. Nest شامل یک لایه استثنایی است که مسئول رسیدگی به همه استثناهای کنترل نشده در یک برنامه است. هنگامی که یک استثنا توسط کد برنامه شما مدیریت نمی شود، توسط این لایه گرفته می شود، که به طور خودکار یک پاسخ کاربر پسند مناسب را ارسال می کند.
همچنین با Nest از پشتیبانی آسان MongoDB برخوردار می شوید. بسیاری از برنامه های وب ساخته شده با Node از استک MEAN استفاده می کنند که از MongoDB، Express، Angular و Node تشکیل شده است. یکی از محبوب ترین کتابخانه ها برای دسترسی به پایگاه داده Mongo، Mongoose است. می توانید به راحتی به پایگاه داده MongoDB متصل شوید و از آن برای ساخت برنامه های مقیاس پذیر با استفاده از بسته NestJS Mongoose استفاده کنید.
در نهایت، همانطور که قبلاً نیز اشاره کردیم، NestJS از چارچوب Express به طور پیش فرض به عنوان pipeline پردازش درخواست استفاده می کند. این بدان معناست که اگر قبلاً با پردازش Express آشنا هستید، میتوانید میدلور Express خود را برای استفاده در Nest تطبیق دهید.
نحوه استفاده NestJS از Express
NestJS را می توان برای استفاده از Express یا Fastify به عنوان چارچوب سرور HTTP خود پیکربندی کرد و به طور پیش فرض از Express استفاده می کند. وظیفه اصلی Express (یا سرور HTTP انتخابی) در NestJS، پروکسی میدلور پیکربندی شده برای مسیرها و مپ کنترلر درخواستهای HTTP به سرور است.
در حالی که انتخاب بین Express یا Fastify به عنوان سرور HTTP پیکربندی شده در پروژه NestJS شما تأثیر کمی دارد، جدا از چند خط کد اضافی برای Fastify - Express به دلیل پشتیبانی جامعه و دسترسی به چندین کتابخانه، به ویژه میدلور و پلاگین هایی که برای کار با Express ساخته شده اند.
Express.js چیست؟
Express یک چارچوب برنامه کاربردی وب Node.js است که طیف گسترده ای از عملکردها را برای ساخت برنامه های وب و موبایل ارائه می دهد. این یک لایه ساخته شده در بالای Node است که به مدیریت سرورها و مسیرها کمک می کند.
می توانید از Express با Node برای ایجاد برنامه های وب تک صفحه ای، چند صفحه ای یا ترکیبی استفاده کنید. از الگوی معماری MVC برای طراحی برنامه های کاربردی وب پشتیبانی می کند: Model، View و Controller.
نحوه نصب Express.js
برای استفاده از Express برای پروژه خود، ابتدا باید آن را نصب کنیم:
npm install express
سپس می خواهیم Express را در پروژه خود وارد کنیم:
import express from 'express';
در مرحله بعد، ما باید برنامه خود را مقداردهی اولیه کنیم، به آن پورتی بدهیم تا به آن گوش دهد و به درخواستی در آن مسیر پاسخ دهیم:
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () =>
console.log('Example app listening on port 3000!'),
);
ویژگی های Express.js
Middleware یک جزء برنامه است که به پایگاه داده، درخواست های کلاینت و سایر میدلورها دسترسی دارد. در درجه اول مسئول سازماندهی سیستماتیک توابع مختلف Express.js است.
هنگامی که صحبت از مسیریابی به میان می آید، Express شامل یک مکانیسم مسیریابی پیچیده است که از URL ها برای حفظ وضعیت صفحه وب استفاده می کند.
در نهایت، Express شامل موتورهای قالب است که توسعه دهندگان را قادر می سازد تا با ایجاد قالب های HTML در سمت سرور، محتوای پویا برای صفحات وب ایجاد کنند.
NestJS در مقابل Express.js
در این بخش، ما به طور مستقیم جنبه های مختلف Nest و Express را با هم مقایسه خواهیم کرد، از جمله موارد استفاده مثال برای هر یک.
Opinionated و un-opinionated
Nest چارچوبی با آپشن های قوی است. به پارادایم طراحی "کنوانسیون روی پیکربندی" پایبند است، که به توسعه دهندگان اجازه می دهد تا از ابزارها و کدهای استاندارد به شیوه ای خاص استفاده کنند، بنابراین نیاز به پیکربندی صریح را کاهش می دهد.
علاوه بر این، NestJS مبتنی بر Angular است، بنابراین TypeScript زبان برنامهنویسی اصلی آن است، اگرچه میتوانید از جاوا اسکریپت نیز استفاده کنید. استفاده از TypeScript تضمین می کند که برنامه قابل اعتماد و بدون باگ است.
Express.js یک چارچوب un-opinionated قوی است، به عبارت دیگر، بدون آپشن. این بدان معنی است که مجموعه ای از قوانین از پیش تعریف شده برای پیروی ندارد. توسعه دهندگان اغلب از این فرصت برای آزمایش سناریوهای مختلف و نوشتن کد در صورت نیاز استفاده می کنند.
محبوبیت
وقتی صحبت از محبوبترین فریمورک میشود، Nest عنوان را به خود میگیرد. با بیش از 64000 ستاره در GitHub، Nest محبوب ترین فریم ورک است.
اکسپرس از نزدیک به دنبال آن است. بیش از 63000 ستاره در GitHub دارد که در میان برترین فریمورک های Node.js توسط ستاره های GitHub در رتبه دوم قرار دارد.
عملکرد
Express می تواند چندین عملیات را مستقل از یکدیگر با استفاده از برنامه نویسی ناهمزمان اجرا کند. Nest به طور پیش فرض از چارچوب Express استفاده می کند.
با این حال، Nest همچنین یک راه جایگزین برای تغییر چارچوب اساسی از Express به Fastify برای بهبود عملکرد قابل توجهی ارائه می دهد.
معماری
Nest با استفاده از کنترلر ها، پروایدر ها و ماژولها، معماری برنامهای آماده برای استفاده را ارائه میکند. این به توسعه دهندگان و تیم ها امکان می دهد برنامه هایی ایجاد کنند که آزمایش و نگهداری آن ها ساده باشد.
Express به ساختار خاصی نیاز ندارد، که می تواند انعطاف پذیری را برای تیم های توسعه کوچک یا تک نفره فراهم کند. با این حال، با افزایش اندازه تیم یا پیچیدگی برنامه، این می تواند به یک مشکل تبدیل شود، به خصوص با توسعه دهندگانی که روی جنبه های مختلف برنامه کار می کنند.
تست واحد
Nest CLI دارای یک محیط تست پیش فرض مبتنی بر Jest است. هنگامی که یک سرویس، رهگیر یا کنترلر ایجاد می شود، CLI یک فایل مشخصات ایجاد می کند. این فایل شامل کد بستر تست تولید شده به صورت خودکار است که نیازی به برنامهنویسان برای نوشتن کد اضافی برای تست واحد را از بین میبرد.
در Express، تست واحد نیاز به ساخت کدهای مجزا دارد، که زمان می برد و ممکن است بهره وری برنامه را کاهش دهد.
موارد استفاده
برخی از نمونههایی از آنچه باید با NestJS بسازید شامل برنامههای کاربردی وب در سطح سازمانی و برنامههای کاربردی تجارت الکترونیک است. برنامه های NestJS به خوبی مقیاس می شوند، و آنها را برای برنامه های بزرگ و در سطح سازمانی عالی می کند. جای تعجب نیست که شرکت های پیشرو مانند آدیداس، روشه، تریلون و دیگران از Nest استفاده می کنند.
همچنین میتوانیم با ترکیب NestJS با یک فریمورک frontend مانند React، Angular یا Vue، وبسایتهای تجارت الکترونیکی را به راحتی بسازیم.
نمونه هایی از آنچه می توانید با Express.js بسازید شامل برنامه های کاربردی فین تک و برنامه های پخش جریانی است. نرمافزار رایانهای یا فناوری دیگری که برای بک اند یا تسهیل خدمات بانکی و مالی استفاده میشود، فینتک نامیده میشود. موسسات مالی بیشتر و بیشتری در حال ایجاد برنامه های کاربردی فین تک هستند و Express چارچوب انتخابی برای ایجاد برنامه های مالی بسیار مقیاس پذیر است.
سرویسهای پخش زمان واقعی پیچیده هستند، با سطوح مختلف جریان داده. برای ایجاد چنین برنامه ای، به یک چارچوب قوی مانند Express.js نیاز دارید که بتواند به طور موثر جریان های داده ناهمزمان را مدیریت کند.
مهاجرت از Express.js به NestJS
بیایید تصور کنیم تا اینجا پیش رفته اید و تصمیم گرفته اید که می خواهید پروژه Express خود را به NestJS منتقل کنید. در این بخش، چند مرحله و مثال برای انتقال پروژه شما به NestJS انجام می دهیم.
قبل از شروع نوشتن هر کدی، اولین چیزی که نیاز داریم این است که در مورد ساختار پروژه خود تصمیم گیری کنیم. Nest اساساً به نحوه سازماندهی یک پروژه (در NestJS آنها را در ماژول ها سازماندهی می کنیم) و وابستگی هایی که بین آنها وجود دارد متکی است. برای جلوگیری از وابستگی دایرهای، باید از قبل به این موضوع فکر کنیم.
هنگامی که تصمیم گرفتیم پروژه خود را چگونه ساختار دهیم، می توانیم به نوشتن کد ادامه دهیم!
برای هدف این بخش و چند نمونه کد، بیایید تصور کنیم که یک سرویس API کتاب آشپزی را منتقل می کنیم و دو منبع را به NestJS منتقل می کنیم، یکی برای ایجاد یک دستور پخت (POST) و دیگری برای بازگرداندن لیستی از دستور العمل ها (GET).
ایجاد و سازماندهی پروژه جدید Nest
اول از همه، بیایید پروژه Nest جدید خود را با اجرای این ایجاد کنیم:
$ nest new coobook-api
در مرحله بعد، ما ماژول های خود را با ایجاد دایرکتوری ماژول دستور العمل ها راه اندازی می کنیم. برای این پروژه، ما تنها یک ماژول خواهیم داشت: recipes
:
$ cd cookbook-api/src
$ mkdir recipes
هر ماژول در NestJS دارای یک کلاس ماژول است که با دکوراتور ()Module@
نوشته شده است که ما ماژول خود را با تعریف اجزای آن سازماندهی می کنیم. فایل ماژول دستور پخت ما recipes.module.ts
نامیده می شود و حاوی موارد زیر است:
// recipes.module.ts
import { Module } from '@nestjs/common';
import { RecipesController } from './recipes.controller';
@Module({})
export class RecipesModule {}
در این مرحله از مهاجرت، ما هنوز هیچ کنترلر یا پروایدر ای ایجاد نکرده ایم، بنابراین کاملاً خالی است.
انتقال مسیرهای ما به کنترلر Nest
اکنون، میتوانیم با ترجمه مسیرهای Express خود در کنترلر NestJS، شروع به نوشتن کد کنیم.
در اینجا فایل مسیر دستور اکسپرس ما است:
// recipes.ts
import { Router, Request, Response } from 'express'
import { GetAllRecipesFilters } from '../../db/dal/types'
import * as controller from '../controllers/recipes'
import { CreateRecipeDTO } from '../dto/recipe.dto'
import {checkCache} from '../../lib/check-cache'
const recipesRouter = Router()
// listing resource
recipesRouter.get('/', checkCache, async (req: Request, res: Response) => {
const filters: GetAllRecipesFilters = req.query
const results = await controller.getAll(filters)
return res.status(200).send(results)
})
// creating resource
recipesRouter.post('/', async (req: Request, res: Response) => {
const payload: CreateRecipeDTO = req.body
const result = await controller.create(payload)
return res.status(200).send(result)
})
در NestJS، یک کنترلر جدید recipes.controller.ts
در ماژول دستورات خود ایجاد خواهیم کرد تا این منابع را در خود جای دهد:
// recipes.controller.ts
import { Body, Controller, Get, Inject, Post, Query } from '@nestjs/common';
import { CreateRecipeDTO, RecipesFilterDto } from './recipes.dto';
import { RecipeEntity } from './recipe.entity';
import { RecipesService } from './recipes.service';
@Controller('recipes')
export class RecipesController {
constructor(@Inject(RecipesService) private recipesService: RecipesService) {}
@Get()
getAll(@Query() filters: RecipesFilterDto): Promise<RecipeEntity[]> {
return this.recipesService.findAll(filters);
}
@Post()
create(@Body() payload: CreateRecipeDTO): Promise<RecipeEntity> {
return this.recipesService.create(payload);
}
}
در بالا، متد GET و POST پشتیبانی شده خود را با استفاده از دکوراتورهای Nest تعریف کردیم تا عملکرد هر منبع را مشخص کنیم. ما همچنین یک رابط شی برای فیلترهای منبع لیست خود در فایل DTO recipes.dto.ts
با استفاده از ()Query@
و همچنین یک نوع DTO برای بار ایجاد شده با استفاده از دکوراتور ()Body@
تعریف کردیم.
برای تمیز نگه داشتن موارد، منطق اجرای منابع خود را خارج از کنترلر و در یک فایل سرویس اختصاصی recipes.service.ts
نگه می داریم، اما برای اختصار، محتوای فایل سرویس را کاوش نمی کنیم. در اینجا می توانید محتویات فایل recipes.service.ts
را بیابید.
DTO مخفف عبارت انتقال داده است. در فایل DTO خود، ما تعریف می کنیم که چه نقاط داده ای را از کاربران API خود نیاز داریم و پشتیبانی می کنیم. این تمرین خوبی برای جدا کردن قرارداد منبع API از منطق داخلی است.
مهاجرت میدلور ها
اکنون که کنترلر داریم و منطق منابع ما در سرویسها، بخش مهم بعدی پروژه Express ما انتقال میدلور است.
Express API ما از میدلوری به نام checkCache
استفاده میکرد که بهجای کوئری مجدد از پایگاهداده ما، نتایج ذخیرهشده را در صورت وجود بررسی میکرد و برمیگرداند. در این مرحله از مهاجرت، ما این میدلور را در NestJS API خود ایجاد می کنیم.
از آنجا که میدلور checkCache
ما احتمالاً برای هر منبع GET اعمال میشود، ما آن را در ماژول دستور العملها پیادهسازی نمیکنیم. در عوض، ما آن را در یک فایل جدید به نام common
قرار می دهیم، جایی که کد کاربردی مشترک API خود را ذخیره می کنیم:
$ mkdir common
$ cd common
$ mkdir middleware
اکنون فایل check-cache.middleware.ts
را ایجاد می کنیم:
// check-cache.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import LocalCache from '../local-cache';
@Injectable()
export class CheckCacheMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
try {
const { baseUrl, method } = req;
const [, , , cacheKey] = baseUrl.split('/');
if (method === 'GET' && LocalCache.hasKey(cacheKey)) {
const data = LocalCache.get(cacheKey);
return res.status(200).send(data);
}
next();
} catch (err) {
throw err;
}
}
}
اکنون میتوانیم این میدلور چک کش را ثبت کنیم و آن را در منابع مربوطه در کلاس AppModule app.module.ts
خود اعمال کنیم:
// app.module.ts
import {
Module,
NestModule,
MiddlewareConsumer,
RequestMethod,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RecipesModule } from './recipes/recipes.module';
import { CheckCacheMiddleware } from './common/middleware/check-cache.middleware';
@Module({
imports: [RecipesModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(CheckCacheMiddleware)
.forRoutes({ path: 'recipes', method: RequestMethod.GET });
}
}
در کد app.module.ts
بالا، ما میدلور چک کش را با استفاده از گزینه forRoutes
به منابع GET دستور العمل اعمال کردیم.
اگر تصمیم دارید تغییر دهید، مراحل بالا بخشهای اصلی انتقال یک برنامه Express به NestJS را پوشش میدهد!
نتیجه
به گفته برخی از توسعه دهندگان، اگر قبلاً از NestJS استفاده می کنید، از بازی جلوتر هستید. این فریمورک در اوایل به شما مزیت قابل توجهی می دهد و همچنین به شما کمک می کند تا با ساختاردهی مناسب برنامه خود، Node Backend خود را به سطح بعدی ببرید.
با این حال، Express.js یکی از بهترین و محبوب ترین فریم ورک های توسعه Backend است که از جاوا اسکریپت استفاده می کند و احتمالاً برای مدتی به همین شکل باقی خواهد ماند. کدام گزینه را ترجیح می دهید؟ نظرات خود را در بخش نظرات به اشتراک بگذارید!