چطور فقط در 3 ساعت با هوش مصنوعی یک سایت کامل بسازیم!
۰ ثانیه
۰ دقیقه
۰ ساعت
۰ دیدگاه نظر سحر پاشائی
Hapi.js چیست؟ (مقایسه آن با Express.js)
سرفصل‌های مقاله
  • Hapi.js چیست؟
  • چرا Hapi این‌قدر سر و صدا به پا کرده؟
  • شرکت‌هایی که از Hapi استفاده می‌کنن
  • اصول و پایه‌های Hapi
  • پلاگین‌ها
  • مقایسه Express و Hapi
  • چرخه درخواست در Hapi
  • نسخه‌های Hapi: از نسخه 16 تا نسخه 21
  • مثال: یک سرور ساده با Hapi نسخه 21
  • شروع کار با Hapi
  • سوالات متداول
  • جمع‌بندی

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

حالا، توی هر فریمورک وبی، یه سری چیزهای پایه و ضروری هست که باید باشه. توی Node.js هم این چیزهای پایه مثل آبجکت‌های درخواست و پاسخ (request و response)، مدیریت درخواست‌های HTTP، ارتباط با دیتابیس از طریق ORM‌ها (یه جور ابزار برای کار با دیتابیس)، و کتابخونه‌هایی برای راه‌اندازی اپلیکیشن توی محیط واقعی وجود داره. اپلیکیشن‌هایی که فقط با Node ساخته می‌شن، خیلی سریع هستن، ولی یه مشکل دارن: کمبود یه سری امکانات مهم مثل میدل‌ویر (که برای پردازش درخواست‌ها بین مسیر استفاده می‌شه)، مسیر‌دهی (برای مدیریت آدرس‌های مختلف سایت) و پلاگین‌ها (افزونه‌هایی که قابلیت‌های جدید به اپلیکیشن اضافه می‌کنن). این امکانات به برنامه‌نویس‌ها کمک می‌کنن که راحت‌تر و با کد کمتر، یه اپلیکیشن مدرن بسازن.

اینجاست که فریمورک‌های وب وارد صحنه می‌شن و کار رو آسون‌تر می‌کنن! تو این مطلب می‌خوایم درباره Hapi.js صحبت کنیم؛ یه فریمورکی که داره به‌ سرعت معروف می‌شه. دلیل این محبوبیت چیه؟ پایداری بالا و این که خیلی راحت می‌تونی باهاش اپلیکیشن‌های بزرگ و قابل گسترش بسازی. حالا بیا با هم بیشتر در مورد این فریمورک جذاب بخونیم.

Hapi.js چیست؟

Hapi.js (کوتاه‌شده‌ی Http-API، تلفظش همون “هپی” یعنی شاد!) یه فریمورک متن‌باز برای ساختن اپلیکیشن‌های تحت وب مقیاس‌پذیر هست. یکی از ساده‌ترین کاربردهای Hapi، ساختن REST API‌هاست. با Hapi.js می‌تونی سرورهای API، سایت‌ها و حتی برنامه‌های پروکسی HTTP بسازی.

این فریمورک توسط تیم موبایل شرکت Walmart Labs به رهبری Eran Hammer ساخته شد تا بتونه ترافیک سنگینی مثل بلک فرایدی رو مدیریت کنه؛ همون روزی که یکی از شلوغ‌ترین روزهای خرید آنلاین در تقویم آمریکا هست!

چرا Hapi این‌قدر سر و صدا به پا کرده؟

بذار یه مثال بزنم تا بفهمی چرا برنامه‌نویس‌ها Hapi رو انقدر قوی و مطمئن می‌دونن. Hapi تونست توی بلک فرایدی، که شلوغ‌ترین روز خرید سال توی آمریکا هست، میلیون‌ها تراکنش خرید، برگشت کالا و خیلی چیزهای دیگه رو تو Walmart مدیریت کنه، بدون اینکه مشکلی پیش بیاد.

تو بلک فرایدی، Hapi تمام ترافیک موبایل Walmart رو با ۱۰ هسته پردازنده (CPU) و ۲۸ گیگابایت رم هندل کرد. البته منابع بیشتری هم داشتیم، ولی بیشترشون فقط ۰.۷۵٪ مشغول بودن و عملاً بیکار بودن! یعنی حجم عظیمی از ترافیک با منابع خیلی کم مدیریت شد. ایران همر، خالق Hapi، این رو یه دستاورد شگفت‌انگیز می‌دونه.

نسخه‌های اولیه Hapi با استفاده از فریمورک Express ساخته شده بود، ولی تیم Walmart فهمیدن که Express یه سری محدودیت داره و نمی‌تونه همه نیازهای پیچیده‌شون رو برآورده کنه. واسه همین، Hapi رو به‌عنوان یه فریمورک مستقل توسعه دادن که حالا دیگه به Express وابسته نیست.

شرکت‌هایی که از Hapi استفاده می‌کنن

Walmart تنها شرکتی نیست که از Hapi استفاده می‌کنه. برندهای بزرگ دیگه‌ای هم هستن که Hapi رو توی پروژه‌های تولیدی خودشون به کار گرفتن و از امکانات و قابلیت‌های فوق‌العاده‌اش بهره می‌برن:

  • Alphamantis
  • YLD
  • Beyonk
  • Octovis
  • Liaison
  • Modulus
  • Icicle Technologies
  • Worldline (ارائه‌دهنده خدمات پرداخت الکترونیک)
  • Macy's (یکی از بزرگترین فروشگاه‌های زنجیره‌ای آمریکا)
  • GetHuman
  • Tagboard

اصول و پایه‌های Hapi

توی مسیر بازسازی سرویس‌های موبایلی Walmart و کار با فریمورک‌های مختلف، اونا به یه سری اصول کلیدی رسیدن که برای ساخت اپلیکیشن‌های Node خیلی مهم بودن؛ اصولی که باعث می‌شد کدها ساده، قابل نگهداری و مقیاس‌پذیر باشن. نتیجه این شد که تیم توسعه Hapi، این فریمورک رو بر اساس چندتا ایده اصلی طراحی کرد:

  • تمرکز روی ساخت ارزش، نه زیرساخت: به‌جای اینکه وقت زیادی رو صرف ساختن ساختارهای پیچیده کنیم، تمرکزمون روی ایجاد ارزش و امکانات مهم برای کاربران باشه.
  • تنظیمات بهتر از کدنویسیه: به جای نوشتن کدهای اضافی، بهتره که همه‌ چیز رو با تنظیمات درست و دقیق مدیریت کنیم.
  • جدا کردن منطق کسب‌وکار از لایه حمل‌ونقل (Transport Layer): یعنی بخشی که مربوط به سرویس‌دهی و درخواست‌هاست، باید از بخش اصلی منطق برنامه جدا باشه.
  • متن‌باز بودن و محوریت جامعه کاربری: Hapi به‌عنوان یه پروژه متن‌باز طراحی شده و همیشه به نظرات و کمک‌های جامعه برنامه‌نویس‌ها اهمیت می‌ده.
  • اکوسیستم کامل (نظر خاص فریمورک، پلاگین‌ها): Hapi اکوسیستم خاص خودش رو داره که پر از پلاگین‌ها و ابزارهاییه که توسعه رو راحت‌تر می‌کنن.
  • ماژول‌های کوچک و منعطف: هر بخش از Hapi به‌صورت ماژول‌های کوچک طراحی شده تا راحت‌تر بتونی اون‌ها رو مدیریت و به‌روزرسانی کنی.

پلاگین‌ها

Hapi یه سیستم پلاگین خیلی قوی داره که بهت اجازه می‌ده خیلی راحت قابلیت‌های جدید به اپلیکیشن اضافه کنی و مشکلات رو سریع برطرف کنی. برای Hapi کلی پلاگین وجود داره که از مستندسازی گرفته تا احراز هویت و کلی چیزای دیگه رو شامل می‌شه. چند تا از مهم‌ترین پلاگین‌ها رو اینجا برات معرفی می‌کنم.

یکی از بزرگ‌ترین مزایای تقسیم کد به پلاگین‌ها اینه که نه‌تنها به نفع کد خودته، بلکه به بقیه هم اجازه می‌ده که از کدهای مشترکی که مفیده استفاده کنن. مثلاً ممکنه یه پلاگین مخصوص احراز هویت فیسبوک (مثل bell) بنویسی یا یه پلاگین خیلی ساده که وقتی سرور بالا میاد، مسیرها رو نشون بده (مثل blipp).

یکی دیگه از خوبی‌های سیستم پلاگین Hapi اینه که تو رو به یه روش خاص محدود نمی‌کنه. اگه بعداً یه پلاگین بهتر پیدا کنی، خیلی راحت می‌تونی اون رو جایگزین کنی بدون اینکه کدهای اصلی پروژه به هم بریزه. این ماجرا نه‌تنها برای پلاگین‌های شخص ثالث صدق می‌کنه، بلکه برای پلاگین‌های خودت هم همین‌طوره.

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

حالا بیایم چندتا از پلاگین‌های مهم Hapi رو معرفی کنیم که بهت کمک می‌کنن قابلیت‌های جدید به اپلیکیشن اضافه کنی:

  • bell: پلاگین احراز هویت برای اتصال به سرویس‌هایی مثل فیسبوک، گوگل و دیگر پلتفرم‌های خارجی. این پلاگین به راحتی احراز هویت رو برای اپلیکیشن‌ها فراهم می‌کنه.
  • blipp: این پلاگین مسیرها (Routes) رو وقتی سرور راه‌اندازی می‌شه، نمایش می‌ده. برای اینکه بدونی اپلیکیشنت از چه مسیرهایی پشتیبانی می‌کنه، فوق‌العاده کارآمده.
  • inert: برای مدیریت و سرو کردن فایل‌های استاتیک مثل تصاویر، فایل‌های CSS یا جاوااسکریپت استفاده می‌شه.
  • vision: پلاگینی برای مدیریت view‌ها (نماها) که با قالب‌های مختلف مثل Handlebars و EJS کار می‌کنه.
  • hapi-auth-jwt2: پلاگین امنیتی برای احراز هویت به وسیله JWT (JSON Web Token) که یکی از روش‌های امن و محبوب برای مدیریت دسترسی‌هاست.

این پلاگین‌ها کمک می‌کنن تا خیلی سریع و با کدهای کم، قابلیت‌های پیشرفته‌ای به اپلیکیشنت اضافه کنی و کار رو برای تیم توسعه راحت‌تر کنی.

مقایسه Express و Hapi

هر دو فریمورک Express و Hapi قصد دارن ساده، انعطاف‌پذیر و قابل‌گسترش باشن. به همین خاطر، کار با هر دوی اون‌ها آسونه و به راحتی می‌تونی به کمک API‌های ساده و مدولار، اپلیکیشنت رو توسعه بدی. اگر با یکی از این فریمورک‌ها کار کرده باشی، یادگیری اون یکی برات خیلی سخت نخواهد بود.

اما تفاوت‌هایی هم بینشون وجود داره:

  • Hapi به‌صورت پیش‌فرض امکانات بیشتری نسبت به Express ارائه می‌ده. مثلاً برای پردازش داده‌های فرم در Express باید از body-parser استفاده کنی، اما در Hapi این کار رو خود فریمورک برات انجام می‌ده.
  • در Express، برای مدیریت درخواست‌ها باید از میدل‌ویر استفاده کنی، اما Hapi از پلاگین‌ها برای ارائه همین قابلیت‌ها بهره می‌بره.
  • برای ارائه و دسترسی به فایل‌های استاتیک، Express از express.static استفاده می‌کنه و Hapi از پلاگین Inert بهره می‌بره.

در نهایت، اگه دنبال یه راه ساده‌تر و با تنظیمات پیش‌فرض امن هستی، Hapi می‌تونه برات مناسب باشه. اما اگه انعطاف بیشتری می‌خوای و دوست داری همه تصمیمات توسعه رو خودت بگیری، Express می‌تونه گزینه بهتری باشه.

چرخه درخواست در Hapi

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

تو چرخه درخواست Hapi، برنامه‌نویس‌ها از hooks یا همون نقاط اتصال مثل handlers و extensions استفاده می‌کنن تا منطق موردنظرشون رو پیاده کنن. این ساختار کمک می‌کنه تا با رشد پیچیدگی پروژه، Hapi به‌عنوان یک رابط واسط عمل کنه و بخش‌های مختلف منطق تجاری به واحدهای کوچک‌تر و قابل مدیریت تقسیم بشه.

نسخه‌های Hapi: از نسخه 16 تا نسخه 21

از زمان انتشار Hapi نسخه 16 تا نسخه‌های جدیدتر مثل 21، تغییرات اساسی تو این فریمورک اتفاق افتاده. یکی از بزرگ‌ترین تغییرات در نسخه 17 بود که Hapi از callbacks به async/await تغییر کرد. این تغییر، برنامه‌نویسی با Hapi رو خیلی ساده‌تر و بهینه‌تر کرد، مخصوصاً برای پروژه‌های بزرگ.

در حال حاضر، آخرین نسخه Hapi، نسخه 21.3.10 هست (منتشر شده در سال 2024)، که از ویژگی‌های جدیدی مثل پشتیبانی از Node.js نسخه 18 و بهبودهای مختلف در سازگاری با ESM (ماژول‌های استاندارد جاوااسکریپت) برخورداره. همینطور، از Node.js نسخه 12 و پایین‌تر دیگه پشتیبانی نمی‌کنه، پس بهتره مطمئن بشی که پروژت با نسخه‌های جدید Node کار می‌کنه.

مثال: یک سرور ساده با Hapi نسخه 21

حالا با استفاده از این نسخه جدید، همچنان می‌تونی خیلی راحت یه سرور ساده API بسازی. برای مثال، همون سرور ساده‌ای که توی ورژن‌های قبلی هم بود، با چند تغییر جزئی هنوز هم قابل اجراست. اما حالا باید از ویژگی‌های به‌روز Hapi استفاده کنی تا بهترین کارایی رو داشته باشی.

'use strict';
const Hapi = require('@hapi/hapi');
const server = Hapi.server({
    port: 3000,
    host: 'localhost'
});
server.route({
    method: 'GET',
    path: '/',
    handler: (request, h) => {
        return 'Hello, world!';
    }
});
server.route({
    method: 'GET',
    path: '/{name}',
    handler: (request, h) => {
        return `Hello, ${encodeURIComponent(request.params.name)}!`;
    }
});
const init = async () => {
    await server.start();
    console.log(`Server running at: ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
    console.log(err);
    process.exit(1);
});
init();

این سرور رو با دستور node server.js اجرا کن و به آدرس http://localhost:3000 برو تا پیام Hello, world! رو ببینی. اگه به http://localhost:3000/yourname بری، با پیامی مثل Hello, yourname! مواجه می‌شی.

نکات جدید برای مهاجرت به نسخه‌های بالاتر

چند نکته مهم برای مهاجرت به نسخه‌های بالاتر:

  • پشتیبانی از Node.js 18: مطمئن شو که پروژت با نسخه‌های جدید Node سازگار هست.
  • تغییرات در پلاگین‌ها: اگه از پلاگین‌هایی مثل catbox-redis استفاده می‌کنی، باید کدت رو برای استفاده از API جدید به‌روز کنی.
  • امنیت بیشتر: Hapi حالا برخی از روش‌های قدیمی مثل JSONP رو حذف کرده و به جای اون از CORS استفاده می‌کنه.

شروع کار با Hapi

برای شروع یه پروژه ساده با Hapi، اول باید یه پوشه جدید به اسم /hapi بسازی و واردش بشی. برای این کار، از دستور زیر استفاده کن:

npm init -y
npm install @hapi/hapi

این دستور یه فایل package.json جدید می‌سازه و Hapi رو به عنوان وابستگی (dependency) نصب می‌کنه. بعد از نصب، می‌تونی با لیست کردن محتویات پوشه /node_modules ببینی که فقط پوشه hapi داخلش قرار گرفته و Hapi به‌ درستی نصب شده.

اضافه کردن یک Endpoint ساده

حالا بریم سراغ اضافه کردن اولین endpoint ساده به سرورمون. قراره که لیستی از دستورهای پخت پاستا رو توی فرمت JSON به صورت RESTful نمایش بدیم. برای این کار، یه فایل به اسم index.js بساز و کدهای زیر رو توش بنویس:

کد index.js برای سرور Hapi

بیاید سراغ کد اصلی که endpoint ساده‌مون رو پیاده‌سازی می‌کنه. تو این قسمت، یه سرور Hapi درست می‌کنیم که لیستی از دستورهای پخت پاستا رو به‌صورت JSON برمی‌گردونه. کد به این صورته:

const Hapi = require('@hapi/hapi');
const pastaRecipes = [
  { id: 1, name: 'Spaghetti Bolognese' },
  { id: 2, name: 'Fettuccine Alfredo' },
  { id: 3, name: 'Penne Arrabiata' }
];
const init = async () => {
  const server = Hapi.server({
    port: 5173,
    host: '0.0.0.0' // این رو حذف کن تا فقط لوکال‌ هاست رو گوش بده
  });
  server.route({
    method: 'GET',
    path: '/recipes',
    handler: (request, h) => {
      return pastaRecipes;
    }
  });
  await server.start();
  console.log('Server running at:', server.info.uri);
};
init();

چطور این Endpoint رو تست کنیم؟

برای تست کردن این endpoint، کافیه از دستور cURL زیر استفاده کنی یا مستقیماً تو مرورگر آدرس http://localhost:5173/recipes رو وارد کنی:

curl http://localhost:5173/recipes

اگه می‌خوای از دستگاه دیگه‌ای هم وصل شی (مثلاً تو شبکه محلی)، کافیه تو تنظیمات سرور host: '0.0.0.0' رو بذاری تا بتونه به همه رابط‌های شبکه وصل بشه.

توضیحات کد

این کد خیلی ساده و سرراسته:

  • اول از همه، ما با require فریمورک Hapi رو میاریم داخل پروژه.
  • بعدش یه آرایه در حافظه (in-memory) درست می‌کنیم که لیست دستورهای پخت پاستا رو نگه می‌داره.
  • تو تابع init، یه سرور جدید با استفاده از Hapi.server می‌سازیم که روی پورت 5173 گوش می‌ده.
  • سپس با استفاده از server.route یه مسیر (route) جدید تعریف می‌کنیم که وقتی به /recipes درخواست فرستاده می‌شه، لیست دستورهای پخت رو برگردونه.
  • در نهایت، با server.start سرور رو راه‌اندازی می‌کنیم.

این کد یه مثال خیلی خوب از اینه که چطور می‌تونی با چند خط ساده کد، یه API کوچک و کاربردی با Hapi بسازی!

اضافه کردن یک POST با احراز هویت

حالا وقتشه که یه endpoint جدید برای POST اضافه کنیم که بشه باهاش یه دستور پخت جدید به لیست اضافه کرد. این درخواست POST ساده‌ست و قراره یه دستور پخت جدید رو به آرایه دستورها اضافه کنه. اینم کدش:

server.route({
  method: 'POST',
  path: '/recipes',
  handler: (request, h) => {
    const recipe = request.payload;
    recipe.id = pastaRecipes.length + 1; // ID جدید بر اساس تعداد دستورهای فعلی
    pastaRecipes.push(recipe); // اضافه کردن دستور جدید به آرایه
    return recipe; // برگردوندن دستور جدید به عنوان پاسخ
  }
});

برای ارسال درخواست POST، می‌تونی از cURL استفاده کنی. این دستور یه دستور پخت جدید به لیست اضافه می‌کنه:

curl -X POST -d '{"name":"Penne alla Vodka"}' http://localhost:5173/recipes -H 'Content-Type: application/json'

بعد از اینکه این درخواست رو ارسال کردی، اگه دوباره یه GET به /recipes بزنی، می‌بینی که دستور جدید به لیست اضافه شده.

حالا با این تغییر، می‌تونی خیلی راحت با اضافه کردن دستورهای جدید پاستا، یه API کوچیک و کاربردی داشته باشی!

احراز هویت ساده با Hapi

فرض کن می‌خوای فقط کاربرای ادمین بتونن به endpoint POST دسترسی داشته باشن. یکی از راه‌های ساده برای این کار، استفاده از مکانیزم احراز هویت HTTP Basic هست. Hapi به‌راحتی این امکان رو فراهم می‌کنه. حالا با این روش می‌تونیم درخواست‌های POST رو هم با cURL تست کنیم، چه با اطلاعات ورود و چه بدون اون.

کد احراز هویت HTTP Basic

const Hapi = require('@hapi/hapi');
const Bcrypt = require('bcrypt');
const users = {
  john: {
    username: 'john',
    password: '$2a$10$iqJSHD.BGr0E2IxQwYgJmeP3NvhPrXAeLSaGCj6IR/XU5QtjVu5Tm',   // پسورد: 'secret'
    name: 'John Doe',
    id: '2133d32a'
  }
};
const validate = async (request, username, password) => {
  const user = users[username];
  if (!user) {
    return { credentials: null, isValid: false };
  }
  const isValid = await Bcrypt.compare(password, user.password);
  const credentials = { id: user.id, name: user.name };
  return { isValid, credentials };
};
const init = async () => {
  const server = Hapi.server({
    port: 5173,
    host: '0.0.0.0'
  });
  await server.register(require('@hapi/basic'));
  server.auth.strategy('simple', 'basic', { validate });
  server.route({
    method: 'POST',
    path: '/recipes',
    options: {
      auth: 'simple'
    },
    handler: (request, h) => {
      const recipe = request.payload;
      recipe.id = pastaRecipes.length + 1;
      pastaRecipes.push(recipe);
      return recipe;
    },
  });
  await server.start();
  console.log('Server running at:', server.info.uri);
};
init();

چطور این کد کار می‌کنه؟

  • bcrypt رو برای رمزنگاری پسوردها ایمپورت کردیم.
  • یه شیء به اسم users تعریف کردیم که نقش دیتابیس کوچیکمون رو برای نگهداری اطلاعات کاربرا ایفا می‌کنه.
  • پلاگین احراز هویت Hapi رو با دستور await server.register(require('@hapi/basic')) ثبت کردیم.
  • یه تابع validate برای چک کردن نام کاربری و رمز عبور نوشتیم تا اعتبار کاربر رو بررسی کنه.
  • یه استراتژی ساده به اسم simple برای احراز هویت تعریف کردیم و اون رو به تابع validate متصل کردیم.
  • استراتژی احراز هویت رو به endpoint /recipes اضافه کردیم.

اجرای کد

برای اجرای این کد، اول باید سرور رو متوقف کنی و پلاگین bcrypt رو نصب کنی:

npm i bcrypt

حالا سرور رو دوباره اجرا کن:

node index.js

با این کار، هر درخواست POST به /recipes باید اطلاعات ورود معتبر داشته باشه.

تست کردن endpoint امن POST

حالا وقتشه که endpoint امن رو تست کنیم. به کمک دستورات cURL، می‌تونیم ببینیم که چطور این endpoint در برابر درخواست‌های مختلف عمل می‌کنه.

تست‌های مختلف با cURL

  • درخواست بدون اطلاعات احراز هویت:

    وقتی بدون اطلاعات ورود تلاش می‌کنیم درخواست POST بفرستیم، خطای عدم احراز هویت رو دریافت می‌کنیم:

    curl -X POST -H "Content-Type: application/json" -d '{"name": "Penne alla Vodka"}' http://localhost:5173/recipes

    پاسخ:

    {"statusCode":401,"error":"Unauthorized","message":"Missing authentication"}
  • درخواست با اطلاعات ورود اشتباه:

    وقتی اطلاعات کاربری اشتباه باشه (مثلاً پسورد اشتباه)، همچنان اجازه دسترسی نخواهیم داشت:

    curl -X POST -u john:badsecret -H "Content-Type: application/json" -d '{"name": "Penne alla Vodka"}' http://localhost:5173/recipes

    پاسخ:

    {"statusCode":401,"error":"Unauthorized","message":"Bad username or password","attributes":{"error":"Bad username or password"}}
  • درخواست با اطلاعات ورود صحیح:

    وقتی اطلاعات ورود درسته، دستور پخت جدید به لیست اضافه می‌شه:

    curl -X POST -u john:secret -H "Content-Type: application/json" -d '{"name": "Penne alla Vodka"}' http://localhost:5173/recipes

    پاسخ:

    {"name":"Penne alla Vodka","id":5}

مسیریابی پیشرفته با Hapi

حالا بیایم یه مثال پیچیده‌تر رو بررسی کنیم. تو این قسمت، می‌خوایم از طریق ID بتونیم یک دستور پخت رو از آرایه بگیریم.

کد برای گرفتن دستور پخت با ID

server.route({
    method: 'GET',
    path: '/recipes/{id}',
    handler: (request, h) => {
      const recipeId = parseInt(request.params.id);
      const recipe = pastaRecipes.find(recipe => recipe.id === recipeId);
      if (recipe) {
        return recipe;
      } else {
        return h.response({ error: 'Recipe not found' }).code(404);
      }
    }
  });

تست این endpoint با cURL:

برای دریافت یه دستور پخت بر اساس ID، می‌تونیم این دستور cURL رو اجرا کنیم:

curl http://localhost:5173/recipes/1

پاسخ:

{"id":1,"name":"Fettuccine Alfredo"}

در اینجا، از پارامتر {id} استفاده کردیم تا یه مقدار از URL بگیریم و بر اساس اون، دستور پخت رو از آرایه پیدا کنیم. اگه دستور پختی با اون ID موجود باشه، برمی‌گرده وگرنه یه پیام خطای 404 دریافت می‌کنی.

کش داخلی در Hapi

Hapi از همون ابتدا پشتیبانی از کش رو به‌صورت داخلی داره. برای مثال، می‌تونیم از کش درون حافظه‌ای با نام CatBoxMemory استفاده کنیم. البته در اپلیکیشن‌های واقعی معمولاً از سیستم‌های کشی مثل Redis یا Memcached استفاده می‌کنن، ولی برای شروع همین CatBoxMemory عالیه.

برای استفاده از کش، باید با متد server.cache() یه کش جدید بسازی و اون رو به مسیرها (routes) اعمال کنی. اینم یه نمونه ساده از استفاده از کش در Hapi:

مثال استفاده از کش

const CatboxMemory = require('@hapi/catbox-memory');
const cache = server.cache({
  segment: 'recipes',
  expiresIn: 60 * 60 * 1000, // کش برای 1 ساعت
  generateFunc: async (recipeId) => {
    const recipe = pastaRecipes.find((recipe) => recipe.id === recipeId);
    return recipe ? { ...recipe, cacheHit: true } : null;
  },
  generateTimeout: 2000
});
server.route({
  method: 'GET',
  path: '/recipes',
  handler: async (request, h) => {
    const cachedRecipes = await cache.get('all');
    if (cachedRecipes) {
      return cachedRecipes;
    }
    await cache.set('all', { ...pastaRecipes, cacheHit: true });
    return pastaRecipes;
  }
});

چی کار می‌کنه؟

توی این کد:

  • ابتدا کش رو با استفاده از متد cache.get بررسی می‌کنیم که آیا دستورهای پخت قبلاً کش شدن یا نه.
  • اگه توی کش باشن، داده‌های کش شده رو برمی‌گردونیم. در غیر این صورت، دستورهای پخت رو از دیتابیس یا آرایه دریافت می‌کنیم و بعد اونا رو کش می‌کنیم.
  • یه فیلد جدید به اسم cacheHit هم به داده‌ها اضافه می‌کنیم تا متوجه بشیم که آیا داده از کش اومده یا مستقیماً از منبع.

تست کش با cURL

حالا می‌تونیم کش رو تست کنیم:

curl localhost:5173/recipes

پاسخ اول:

[{"id":0,"name":"Spaghetti Bolognese"},{"id":1,"name":"Fettuccine Alfredo"},{"id":2,"name":"Penne Arrabiata"}]

پاسخ بعد از استفاده از کش:

{"0":{"id":0,"name":"Spaghetti Bolognese"},"1":{"id":1,"name":"Fettuccine Alfredo"},"2":{"id":2,"name":"Penne Arrabiata"},"cacheHit":true}

در اینجا می‌بینی که توی پاسخ دوم فیلد cacheHit اضافه شده، که نشون می‌ده داده‌ها از کش گرفته شدن و نه مستقیماً از دیتابیس یا آرایه. این باعث می‌شه که عملکرد اپلیکیشن سریع‌تر و بهینه‌تر بشه.

متد سرور Hapi—یک کش ساده‌تر

Hapi یه قابلیت جالب به اسم server method داره که به‌طور ساده‌تری می‌تونی برای کش کردن نتایج استفاده کنی. فرض کن می‌خوای برای endpoint که دستورهای پخت رو بر اساس ID می‌گیره، کش اضافه کنی. به‌جای پیچیدگی‌های قبلی، با استفاده از این متد سرور می‌تونیم خیلی راحت‌تر این کار رو انجام بدیم.

نمونه کد استفاده از متد سرور برای کش

const init = async () => {
  const server = Hapi.server({
    port: 5173,
    host: '0.0.0.0'
  });
  server.method('getRecipe', (id) => {
    const recipe = pastaRecipes.find(recipe => recipe.id === id);
    return recipe ? recipe : { error: 'Recipe not found' };
  }, {
    cache: {
      expiresIn: 10 * 1000,  // کش برای 10 ثانیه
      generateTimeout: 2000
    }
  });
  server.route({
    method: 'GET',
    path: '/recipes/{id}',
    handler: async (request, h) => {
      return await server.methods.getRecipe(parseInt(request.params.id));
    }
  });
  await server.start();
  console.log('Server running at:', server.info.uri);
};
init();

چطور کار می‌کنه؟

توی این کد، با استفاده از server.method یه متد جدید به اسم getRecipe تعریف کردیم که دستور پخت رو بر اساس ID پیدا می‌کنه. با اضافه کردن cache به این متد، نتایج درخواست‌ها به‌طور خودکار کش می‌شن و نیاز به نوشتن کدهای اضافی برای مدیریت کش نداریم. پس اگه چند بار به همون ID درخواست بفرستی، نتیجه رو از کش می‌گیره و سریع‌تر برمی‌گردونه.

سوالات متداول

1. چرا باید از Hapi به جای Express استفاده کنم؟

Hapi امکانات بیشتری به‌صورت پیش‌فرض ارائه می‌ده و برای پروژه‌های بزرگ‌تر و تیم‌های چندنفره خیلی مناسب‌تره، چرا که ساختارهای مدولار و پلاگین‌های قوی‌تری داره. از طرف دیگه، Hapi نسبت به Express کنترل بیشتری روی امنیت و کش کردن داده‌ها ارائه می‌ده و نیازی به میدل‌ویرهای اضافی برای بسیاری از وظایف معمول نداره.

2. آیا Hapi برای پروژه‌های کوچک هم مناسب هست؟

بله، Hapi انعطاف‌پذیره و می‌تونی ازش برای پروژه‌های کوچک هم استفاده کنی. هرچند اگه پروژه خیلی ساده‌ای داری، ممکنه Express انتخاب راحت‌تری باشه، چون سبک‌تره. اما اگه به‌دنبال ساختار منظم‌تر و مدیریت بهتر امنیت و کش هستی، Hapi انتخاب عالی‌ایه.

3. چطور می‌تونم کش کردن داده‌ها رو در Hapi فعال کنم؟

Hapi از همون ابتدا با قابلیت کش داخلی ارائه می‌شه. می‌تونی از متد server.cache() یا server.method() برای کش کردن داده‌ها استفاده کنی. همچنین، با پلاگین‌هایی مثل CatBoxMemory یا Redis، می‌تونی داده‌ها رو به‌صورت پیشرفته‌تر کش کنی.

4. آیا Hapi با Node.js نسخه‌های جدید سازگاره؟

بله، نسخه‌های جدید Hapi از Node.js نسخه 14 و بالاتر، به‌ویژه نسخه‌های LTS مثل Node.js 18، کاملاً پشتیبانی می‌کنن. Hapi همیشه به‌روزرسانی می‌شه تا با نسخه‌های جدیدتر Node.js سازگار بمونه و بهترین عملکرد رو ارائه بده.

جمع‌بندی

Hapi واقعاً اون چیزی که از یه API سروری انتظار داری رو بهت می‌ده: ساده، قابل گسترش و بدون نیاز به وابستگی‌های اضافی. پلاگین‌ها و سیستم کش‌ Hapi خیلی تمیز و هدفمند طراحی شده تا نیازی به سروکله زدن با پیچیدگی‌های میدل‌ویر نداشته باشی. همین ویژگی‌هاش باعث می‌شه که Hapi یه گزینه امن و قابل اعتماد برای پروژه‌هات باشه.

۰ دیدگاه
ما همه سوالات و دیدگاه‌ها رو می‌خونیم و پاسخ میدیم

دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد:

۲۰۰ هزار تومان رایگان
دریافت دوره الفبای برنامه نویسی