مقدمه

فریمورک Express.js یکی از محبوب‌ترین فریمورک‌های Backend و محبوب‌ترین فریمورک Node.js است. در این درس، ابتدا یک معرفی کلی از فریمورک Express ارائه می‌دهیم و سپس، از آن برای ایجاد یک وب‌سرور ساده استفاده می‌کنیم.

معرفی فریمورک Express

همانطور که در پایان درس قبل اشاره شد، برای توسعه‌ی اپ با Node.js دو راه داریم. راه اول که با مشقت‌های زیادی همراه است، این است که فرایند توسعه را با Node.js و بدون استفاده از فریمورک‌ها انجام دهیم و راه دوم این است که دست از تلاش برای اختراع مجدد چرخ برداریم و از یک فریمورک که روی ماژول‌های Node.js مانند http نوشته شده، استفاده کنیم.

در مورد توسعه‌ی Frontend، استفاده یا عدم استفاده از فریمورک‌ها بیش از هر چیز به سلیقه‌ی توسعه‌دهنده بستگی دارد و نمی‌توان با قاطعیت از درست یا غلط بودن استفاده از فریمورک‌ها صحبت کرد. اما وقتی پای توسعه‌ی Backend در میان باشد، تقریباً همه‌ی صاحب‌نظران عرصه‌ی توسعه‌ی نرم‌افزار بر استفاده از فریمورک‌ها تأکید دارند.

اولین نسخه از فریمورک Express تقریباً یک سال بعد از انتشار Node.js یعنی اواخر سال 2010 منتشر شد و در حال حاضر، این فریمورک در نسخه‌ی ماژور 4 قرار دارد. سادگی و ماهیت مینیمال این فریمورک باعث محبوبیت آن نزد کاربران شده است. برای یک فریمورک وب، محبوبیت یک عامل کلیدی است؛ چون شاخصی است برای این که آیا توسعه و نگهداری از فریمورک ادامه پیدا می‌کند یا خیر و اینکه وضعیت مستندات، پشتیبانی و کتابخانه‌های جانبی برای آن چطور خواهد بود.

ماهیت مینیمال فریمورک Express

گفتیم یکی از دلایل محبوبیت Express، مینیمال بودن آن است. اجازه دهید کمی بیشتر در این مورد توضیح بدهیم و ببینیم اساساً مینیمال بودن یک فریمورک به چه معناست و چه تبعات منفی و مثبتی دارد.

یک فریمورک وب می‌تواند opinionated یا unopinionated باشد؛ یعنی می‌تواند اهل نظر دادن باشد یا نباشد.

  • فریمورک‌هایی مثل Django که درباره‌ی روش درست برای انجام هر کاری نظراتی دارند، از نوع opinionated هستند. طبیعتاً این دست فریمورک‌ها باید ابزارهای لازم برای مسیرهای پیشنهادی‌شان را در خود داشته باشند و نتیجتاً فریمورک‌های سنگینی خواهند بود.
  • فریمورک‌هایی مانند Express که از نوع unopinionated هستند، چیزی را تحت عنوان بهترین روش دیکته نمی‌کنند و این خود ما هستیم که باید روش مورد نظرمان را انتخاب کنیم. این همان چیزی است که منجر به سبک و مییمال بودن Express شده است.

پس، Express یک فریمورک unopinionated است و شما می‌توانید تقریباً هر middleware سازگار دلخواه را به زنجیره‌ی پردازش درخواست اضافه کنید؛ به هر ترتیبی که دوست دارید. شما می‌توانید اپلیکیشن را در یک فایل یا چند فایل ساختار دهید و از هر ساختار دایرکتوری استفاده کنید. این ویژگی، یک شمشیر دولبه است که از یک طرف انعطاف بیشتری دارد و ما را به یک روش خاص محدود نمی‌کند و از طرف دیگر، می‌تواند با چالش‌هایی برای انتخاب روش و ابزار مناسب همراه باشد.

ساحت یک وب‌سرور با Express

برای استفاده از فریمورک Express، ابتدا باید آن را روی پروژه نصب کنیم. یک پروژه‌ی جدید با نامی دلخواه ایجاد کنید، فایل اصلی آن را app.js بنامید و کامند زیر را از درون دایرکتوری پروژه اجرا کنید.

$ npm install express

بعد از نصب پکیج، کد زیر را در فایل app.js وارد کنید.

Copy Icon app.js
const express = require('express');

const app = express();
            
app.get('/', (req, res) => {
  res.send('Hello From Express');
});
            
app.get('/contact', (req, res) => {
  res.send('The Contact Page');
});
            
app.get('/about', (req, res) => {
  res.send('The About Page');
});
            
const PORT = 3000;
            
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

در اینجا ماژول express را به پروژه وارد (import) کرده‌ایم و سپس، با فراخوانی تابع express() یک اپلیکیشن Express ایجاد کرده‌ایم. در این اپلیکیشن، یک وب‌سرور تعریف شده که مشابه وب‌سروری است که در فصل قبل با استفاده از Node.js ایجاد کرده بودیم. اما این بار به جای استفاده از گزاره‌های if، هر route به صورت مستقل تعریف شده است.

متد app.get() برای پاسخ به درخواست‌های HTTP از نوع GET کاربرد دارد. یک متد مشابه با نام app.post() هم برای مدیریت درخواست‌های از نوع POST قابل استفاده است که در آینده از آن استفاده خواهیم کرد.

آخرین route در کد بالا با استفاده از کاراکتر * ایجاد شده که یک کاراکتر wildcard است و به این معناست که هر درخواستی منجر به تولید کد وضعیت 404 و ارسال یک پیغام Not Found شود. البته با توجه به اینکه در Express ترتیب قرارگیری روت‌ها مهم است، فقط هر درخواستی که با روت‌های قبلی مطابق نباشد، خطای 404 را تولید می‌کند.

در نهایت، استفاده از متد app.listen() باعث شده که سرور بتواند به درخواست‌های ورودی گوش دهد و پاسخ مناسب را برای هر درخواست برگرداند.

اضافه کردن پکیج Morgan

اگر دقت کرده باشید، بر خلاف وب‌سروری که قبلاً با استفاده از Node.js ایجاد کردیم، در اینجا از متد console.log() برای لاگ آدرس URL استفاده نکرده‌ایم. اگر بخواهیم این کار را انجام دهیم، باید با توجه به مستقل بودن روت‌ها از یکدیگر، از متد console.log() برای تک‌تک روت‌ها استفاده کنیم. یعنی:

Copy Icon app.js
app.get('/', (req, res) => {
  console.log(req.url);
  res.send('Hello From Node.js');
});
app.get('/contact', (req, res) => {
  console.log(req.url);
  res.send('The Contact Page');
});

اما به‌جای این کار، می‌توانیم از یک ابزار logger به نام Morgan استفاده کنیم که به طور خودکار و برای هر درخواست، اطلاعاتی را در مورد آن درخواست لاگ می‌کند. برای استفاده از Morgan باید ابتدا آن را نصب کنیم.

$ npm install morgan

حالا در فایل app.js ابتدا این پکیج را به پروژه وارد می‌کنیم و سپس، از یک متد با نام use() به صورت زیر استفاده می‌کنیم.

Copy Icon app.js
const express = require('express');
const morgan = require('morgan');

const app = express();

app.use(morgan('dev'));

            
app.get('/', (req, res) => {
  res.send('Hello From Node.js');
});
            
app.get('/contact', (req, res) => {
  res.send('The Contact Page');
});
            
app.get('/about', (req, res) => {
  res.send('The About Page');
});
            
const PORT = 3000;
            
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

متد use() یک تابع middleware را رجیستر می‌کند تا در هر درخواستی اجرا شود. آرگومان تابع morgan() مشخص‌کننده‌ی فرمت اطلاعاتی است که لاگ می‌شوند. مقادیر دیگری مثل tiny یا common هم قابل استفاده هستند اما برای لاگ در محیط توسعه، بهترین گزینه dev است.

در مورد مفهوم middleware و نقش کلیدی آن در اپلیکیشن‌های Express بعداً صحلت خواهیم کرد اما فعلاً سرور را راه‌اندازی کنید و درخواست‌هایی را با استفاده از یک مرورگر ایجاد کنید. خواهید دید که در هر درخواست، اطلاعاتی مانند متد HTTP مربوط به درخواست، URL درخواست، کد وضعیت (status code) مربوط به پاسخ و زمان لازم برای تولید پاسخ توسط سرور در کنسول نمایش داده می‌شود.

GET / 304 5.390 ms - - 
GET /about 304 0.654 ms - - 
GET /contact 304 0.671 ms - -