فصل ششم: مسیرهای سرور (شبیه‌سازی API)

در این فصل، به پیاده‌سازی مسیرهای سرور (Server Routes) در Nuxt 3 برای شبیه‌سازی APIهای بک‌اند در اپلیکیشن مرکز اجاره کشتی‌های کروز می‌پردازیم. Nuxt 3 با استفاده از موتور Nitro امکان ایجاد APIهای سمت سرور را به‌صورت داخلی فراهم می‌کند، که برای مدیریت داده‌ها بدون نیاز به سرور جداگانه بسیار کاربردی است. در این پروژه، ما دو مسیر API ایجاد می‌کنیم: یکی برای دریافت لیست کشتی‌ها و دیگری برای مدیریت رزروها. این APIها به‌صورت موقت داده‌ها را در حافظه ذخیره می‌کنند، اما در پروژه‌های واقعی می‌توانند به پایگاه داده‌ای مانند Supabase یا Prisma متصل شوند. در ادامه، هر مسیر API به‌طور کامل توضیح داده شده و کدهای مربوطه شرح داده می‌شوند.


API کشتی‌ها (server/api/ships.ts)

این مسیر API وظیفه ارائه لیست کشتی‌های کروز را بر عهده دارد و به‌عنوان یک منبع داده برای صفحه لیست کشتی‌ها و جزئیات کشتی عمل می‌کند.

کد:

// server/api/ships.ts
import type { Ship } from '~/types';

export default defineEventHandler((): Ship[] => {
  return [
    { id: 1, name: 'Ocean Explorer', capacity: 500, pricePerDay: 10000, amenities: ['Pool', 'Gym'], image: '/images/ocean.jpg' },
    { id: 2, name: 'Luxury Liner', capacity: 1000, pricePerDay: 20000, amenities: ['Spa', 'Theater'], image: '/images/luxury.jpg' },
  ];
});

توضیحات:

  1. وارد کردن تایپ Ship:

  2. import type { Ship } from '~/types': تایپ Ship از فایل types/index.ts وارد شده است تا اطمینان حاصل شود که داده‌های بازگشتی با مدل داده Ship (شامل فیلدهای id, name, capacity, pricePerDay, amenities, و image) مطابقت دارند. این کار ایمنی نوع را در TypeScript تضمین می‌کند.

  3. تعریف مسیر:

  4. defineEventHandler((): Ship[] => {...}): از تابع defineEventHandler که بخشی از موتور Nitro در Nuxt 3 است، برای تعریف یک مسیر API استفاده شده است.

  5. این مسیر به‌صورت پیش‌فرض به درخواست‌های GET در آدرس /api/ships پاسخ می‌دهد.
  6. نوع بازگشتی به‌صورت آرایه‌ای از Ship تعریف شده است (Ship[]).

  7. داده‌های موقت:

  8. این مسیر یک آرایه ثابت از دو کشتی نمونه را برمی‌گرداند:

    • کشتی اول: Ocean Explorer با ظرفیت ۵۰۰ نفر، قیمت روزانه ۱۰,۰۰۰ دلار، امکانات استخر و باشگاه، و تصویر /images/ocean.jpg.
    • کشتی دوم: Luxury Liner با ظرفیت ۱,۰۰۰ نفر، قیمت روزانه ۲۰,۰۰۰ دلار، امکانات اسپا و تئاتر، و تصویر /images/luxury.jpg.
  9. مسیرهای تصویر (/images/ocean.jpg و /images/luxury.jpg) به پوشه public/ اشاره دارند، جایی که تصاویر باید ذخیره شوند.

  10. کاربرد:

  11. این API توسط store کشتی‌ها (useShipsStore) در متد fetchShips فراخوانی می‌شود تا داده‌های کشتی‌ها را برای نمایش در صفحه لیست کشتی‌ها (pages/ships/index.vue) و صفحه جزئیات کشتی (pages/ships/[id].vue) فراهم کند.

  12. در یک پروژه واقعی، این داده‌ها می‌توانند از یک پایگاه داده (مانند MongoDB یا PostgreSQL) دریافت شوند.

  13. مزایا:

  14. سادگی: این API نیازی به سرور جداگانه ندارد و مستقیماً در پروژه Nuxt اجرا می‌شود.

  15. انعطاف‌پذیری: می‌توان به‌راحتی آن را به یک پایگاه داده واقعی متصل کرد.
  16. ایمنی نوع: استفاده از TypeScript اطمینان می‌دهد که داده‌های بازگشتی با مدل Ship سازگار هستند.

API رزروها (server/api/bookings.ts)

این مسیر API برای مدیریت رزروهای کاربران طراحی شده است و از درخواست‌های GET (برای دریافت رزروها) و POST (برای افزودن رزرو جدید) پشتیبانی می‌کند.

کد:

// server/api/bookings.ts
import type { Booking } from '~/types';

let bookings: Booking[] = [];

export default defineEventHandler({
  async get() {
    return bookings;
  },
  async post(event) {
    const body = await readBody(event);
    const newBooking: Booking = {
      id: bookings.length + 1,
      shipId: body.shipId,
      startDate: new Date(body.startDate),
      endDate: new Date(body.endDate),
      totalPrice: body.totalPrice,
    };
    bookings.push(newBooking);
    return newBooking;
  },
});

توضیحات:

  1. وارد کردن تایپ Booking:

  2. import type { Booking } from '~/types': تایپ Booking از فایل types/index.ts وارد شده است تا داده‌های رزرو با مدل Booking (شامل فیلدهای id, shipId, startDate, endDate, و totalPrice) مطابقت داشته باشند.

  3. ذخیره‌سازی موقت:

  4. let bookings: Booking[] = []: آرایه‌ای برای ذخیره رزروها در حافظه تعریف شده است. این داده‌ها با هر بار راه‌اندازی مجدد سرور پاک می‌شوند (در پروژه واقعی، باید از پایگاه داده استفاده شود).

  5. تعریف مسیر:

  6. defineEventHandler({...}): یک مسیر API چندمنظوره تعریف می‌کند که به درخواست‌های GET و POST در آدرس /api/bookings پاسخ می‌دهد.

  7. متد GET:

  8. async get(): این متد تمام رزروهای موجود در آرایه bookings را برمی‌گرداند.

  9. کاربرد: توسط store رزروها (useBookingsStore) در متد fetchBookings برای نمایش رزروها در داشبورد رزروها (pages/bookings.vue) استفاده می‌شود.

  10. متد POST:

  11. async post(event): این متد یک رزرو جدید را از بدنه درخواست (Request Body) دریافت کرده و به آرایه bookings اضافه می‌کند.

  12. const body = await readBody(event): بدنه درخواست را می‌خواند که شامل shipId, startDate, endDate, و totalPrice است.
  13. const newBooking: Booking: یک شیء رزرو جدید ایجاد می‌کند:
    • id: به‌صورت خودکار با افزایش تعداد رزروهای موجود (bookings.length + 1) تولید می‌شود.
    • سایر فیلدها (shipId, startDate, endDate, totalPrice) از بدنه درخواست گرفته شده و startDate و endDate به شیء Date تبدیل می‌شوند.
  14. bookings.push(newBooking): رزرو جدید به آرایه اضافه می‌شود.
  15. return newBooking: رزرو جدید به‌عنوان پاسخ به کلاینت ارسال می‌شود.
  16. کاربرد: توسط store رزروها در متد addBooking هنگام ارسال فرم رزرو در صفحه جزئیات کشتی (pages/ships/[id].vue) فراخوانی می‌شود.

  17. کاربرد:

  18. این API امکان افزودن رزروهای جدید و دریافت لیست رزروها را فراهم می‌کند.

  19. در پروژه واقعی، می‌توان آن را به یک پایگاه داده متصل کرد تا رزروها به‌صورت دائمی ذخیره شوند.

  20. مزایا:

  21. یکپارچگی با Nuxt: نیازی به سرور جداگانه نیست و Nitro اجرای سریع و کارآمد را تضمین می‌کند.

  22. پشتیبانی از چندین متد HTTP: این مسیر به‌راحتی از GET و POST پشتیبانی می‌کند و می‌توان متدهای دیگر (مانند PUT یا DELETE) را به آن اضافه کرد.
  23. ایمنی نوع: استفاده از تایپ Booking از خطاهای داده‌ای جلوگیری می‌کند.

نکات تکمیلی

  • شبیه‌سازی در مقابل تولید: در این پروژه، داده‌ها به‌صورت موقت در حافظه ذخیره می‌شوند. برای پروژه‌های واقعی، باید این APIها را به یک پایگاه داده مانند Supabase، MongoDB یا PostgreSQL متصل کنید. برای مثال، می‌توانید از ماژول @nuxtjs/supabase برای اتصال به Supabase استفاده کنید.
  • مقیاس‌پذیری: ساختار مسیرهای سرور Nuxt امکان افزودن منطق پیچیده‌تر (مانند احراز هویت یا اعتبارسنجی داده) را فراهم می‌کند.
  • بهینه‌سازی: Nitro به‌طور خودکار پاسخ‌ها را فشرده‌سازی کرده و عملکرد را بهبود می‌بخشد.

جمع‌بندی فصل ششم

در این فصل، دو مسیر API برای اپلیکیشن مرکز اجاره کشتی‌های کروز پیاده‌سازی کردیم:

  • API کشتی‌ها (/api/ships): لیستی از کشتی‌ها را برای نمایش در رابط کاربری فراهم می‌کند.
  • API رزروها (/api/bookings): امکان دریافت و افزودن رزروها را مدیریت می‌کند.

این مسیرها با استفاده از موتور Nitro و TypeScript پیاده‌سازی شده‌اند تا ایمن، کارآمد و قابل گسترش باشند. در فصل‌های بعدی، به ویژگی‌های پیشرفته‌تر مانند میدلورها و بهینه‌سازی‌های Nuxt خواهیم پرداخت.