Українська

Досліджуйте API-маршрути Next.js та розкрийте можливості повностекової розробки у ваших React-застосунках. Вивчайте патерни, найкращі практики та стратегії розгортання.

API-маршрути Next.js: Патерни повностекової розробки

Next.js здійснив революцію в розробці на React, надавши надійний фреймворк для створення продуктивних і масштабованих вебзастосунків. Однією з його ключових особливостей є API-маршрути, які дозволяють розробникам створювати функціональність бекенду безпосередньо у своїх проєктах Next.js. Цей підхід оптимізує розробку, спрощує розгортання та відкриває потужні можливості повностекової розробки.

Що таке API-маршрути Next.js?

API-маршрути Next.js — це безсерверні функції, написані безпосередньо у вашому каталозі /pages/api. Кожен файл у цьому каталозі стає кінцевою точкою API, автоматично маршрутизуючи HTTP-запити до відповідної функції. Це усуває потребу в окремому сервері бекенду, спрощуючи архітектуру вашого застосунку та зменшуючи операційні витрати.

Уявляйте їх як мініатюрні безсерверні функції, що живуть у вашому застосунку Next.js. Вони відповідають на HTTP-запити, такі як GET, POST, PUT, DELETE, і можуть взаємодіяти з базами даних, зовнішніми API та іншими серверними ресурсами. Важливо, що вони виконуються лише на сервері, а не в браузері користувача, що гарантує безпеку конфіденційних даних, таких як API-ключі.

Ключові переваги API-маршрутів

Початок роботи з API-маршрутами

Створити API-маршрут у Next.js дуже просто. Достатньо створити новий файл у каталозі /pages/api. Ім'я файлу визначатиме шлях маршруту. Наприклад, створення файлу з назвою /pages/api/hello.js створить кінцеву точку API, доступну за адресою /api/hello.

Приклад: Простий API для привітання

Ось базовий приклад API-маршруту, який повертає відповідь у форматі JSON:


// pages/api/hello.js

export default function handler(req, res) {
  res.status(200).json({ message: 'Привіт від API-маршруту Next.js!' });
}

Цей код визначає асинхронну функцію handler, яка отримує два аргументи:

Функція встановлює код стану HTTP на 200 (OK) і повертає відповідь у форматі JSON з повідомленням.

Обробка різних методів HTTP

Ви можете обробляти різні методи HTTP (GET, POST, PUT, DELETE тощо) у вашому API-маршруті, перевіряючи властивість req.method. Це дозволяє легко створювати RESTful API.


// pages/api/todos.js

export default async function handler(req, res) {
  if (req.method === 'GET') {
    // Отримати всі завдання з бази даних
    const todos = await fetchTodos();
    res.status(200).json(todos);
  } else if (req.method === 'POST') {
    // Створити нове завдання
    const newTodo = await createTodo(req.body);
    res.status(201).json(newTodo);
  } else {
    // Обробити непідтримувані методи
    res.status(405).json({ message: 'Метод не дозволено' });
  }
}

Цей приклад демонструє, як обробляти запити GET і POST для гіпотетичної кінцевої точки /api/todos. Він також включає обробку помилок для непідтримуваних методів.

Патерни повностекової розробки з API-маршрутами

API-маршрути Next.js дозволяють реалізовувати різноманітні патерни повностекової розробки. Ось деякі поширені випадки використання:

1. Отримання та маніпуляція даними

API-маршрути можна використовувати для отримання даних з баз даних, зовнішніх API або інших джерел даних. Їх також можна використовувати для маніпуляції даними, наприклад, для створення, оновлення або видалення записів.

Приклад: Отримання даних користувача з бази даних


// pages/api/users/[id].js
import { query } from '../../../lib/db';

export default async function handler(req, res) {
  const { id } = req.query;

  try {
    const results = await query(
      'SELECT * FROM users WHERE id = ?',
      [id]
    );

    if (results.length === 0) {
      return res.status(404).json({ message: 'Користувача не знайдено' });
    }

    res.status(200).json(results[0]);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: 'Внутрішня помилка сервера' });
  }
}

Цей приклад отримує дані користувача з бази даних на основі ідентифікатора користувача, наданого в URL. Він використовує бібліотеку для запитів до бази даних (яка, як передбачається, знаходиться в lib/db) для взаємодії з базою даних. Зверніть увагу на використання параметризованих запитів для запобігання вразливостям до SQL-ін'єкцій.

2. Автентифікація та авторизація

API-маршрути можна використовувати для реалізації логіки автентифікації та авторизації. Ви можете використовувати їх для перевірки облікових даних користувача, генерації JWT-токенів та захисту конфіденційних ресурсів.

Приклад: Автентифікація користувача


// pages/api/login.js
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { query } from '../../lib/db';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { email, password } = req.body;

    try {
      const results = await query(
        'SELECT * FROM users WHERE email = ?',
        [email]
      );

      if (results.length === 0) {
        return res.status(401).json({ message: 'Невірні облікові дані' });
      }

      const user = results[0];

      const passwordMatch = await bcrypt.compare(password, user.password);

      if (!passwordMatch) {
        return res.status(401).json({ message: 'Невірні облікові дані' });
      }

      const token = jwt.sign(
        { userId: user.id, email: user.email },
        process.env.JWT_SECRET,
        { expiresIn: '1h' }
      );

      res.status(200).json({ token });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Внутрішня помилка сервера' });
    }
  } else {
    res.status(405).json({ message: 'Метод не дозволено' });
  }
}

Цей приклад автентифікує користувачів, порівнюючи наданий пароль зі збереженим хешованим паролем у базі даних. Якщо облікові дані дійсні, він генерує JWT-токен і повертає його клієнту. Клієнт може потім використовувати цей токен для автентифікації наступних запитів.

3. Обробка форм та надсилання даних

API-маршрути можна використовувати для обробки надсилань форм та обробки даних, надісланих з клієнта. Це корисно для створення контактних форм, реєстраційних форм та інших інтерактивних елементів.

Приклад: Надсилання контактної форми


// pages/api/contact.js
import { sendEmail } from '../../lib/email';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email, message } = req.body;

    try {
      await sendEmail({
        to: 'admin@example.com',
        subject: 'Нове повідомлення з контактної форми',
        text: `Ім'я: ${name}\nEmail: ${email}\nПовідомлення: ${message}`,
      });

      res.status(200).json({ message: 'Електронний лист успішно надіслано' });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Не вдалося надіслати електронний лист' });
    }
  } else {
    res.status(405).json({ message: 'Метод не дозволено' });
  }
}

Цей приклад обробляє надсилання контактної форми, відправляючи електронний лист адміністратору. Він використовує бібліотеку для надсилання електронних листів (яка, як передбачається, знаходиться в lib/email) для відправки листа. Ви повинні замінити admin@example.com на фактичну адресу електронної пошти одержувача.

4. Вебхуки та обробка подій

API-маршрути можна використовувати для обробки вебхуків та реагування на події від зовнішніх сервісів. Це дозволяє інтегрувати ваш застосунок Next.js з іншими платформами та автоматизувати завдання.

Приклад: Обробка вебхука від Stripe


// pages/api/stripe-webhook.js
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export const config = {
  api: {
    bodyParser: false, // Вимкнути стандартний парсинг тіла запиту
  },
};

async function buffer(req) {
  const chunks = [];
  for await (const chunk of req) {
    chunks.push(chunk);
  }
  return Buffer.concat(chunks).toString();
}

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const sig = req.headers['stripe-signature'];

    let event;

    try {
      const buf = await buffer(req);
      event = stripe.webhooks.constructEvent(buf, sig, process.env.STRIPE_WEBHOOK_SECRET);
    } catch (err) {
      console.log(`Помилка вебхука: ${err.message}`);
      res.status(400).send(`Помилка вебхука: ${err.message}`);
      return;
    }

    // Обробити подію
    switch (event.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = event.data.object;
        console.log(`PaymentIntent на суму ${paymentIntent.amount} був успішним!`);
        // Потім визначити та викликати метод для обробки успішного платіжного наміру.
        // handlePaymentIntentSucceeded(paymentIntent);
        break;
      case 'payment_method.attached':
        const paymentMethod = event.data.object;
        // Потім визначити та викликати метод для обробки успішного прикріплення PaymentMethod.
        // handlePaymentMethodAttached(paymentMethod);
        break;
      default:
        // Неочікуваний тип події
        console.log(`Необроблений тип події ${event.type}.`);
    }

    // Повернути відповідь 200 для підтвердження отримання події
    res.status(200).json({ received: true });
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Метод не дозволено');
  }
}

Цей приклад обробляє вебхук від Stripe, перевіряючи підпис та обробляючи дані події. Він вимикає стандартний парсер тіла запиту та використовує спеціальну функцію буферизації для читання необробленого тіла запиту. Важливо вимкнути стандартний парсер тіла, оскільки Stripe вимагає необроблене тіло для перевірки підпису. Не забудьте налаштувати кінцеву точку вебхука Stripe у вашій панелі керування Stripe та встановити змінну середовища STRIPE_WEBHOOK_SECRET.

Найкращі практики для API-маршрутів

Щоб забезпечити якість та зручність підтримки ваших API-маршрутів, дотримуйтесь цих найкращих практик:

1. Модуляризуйте свій код

Уникайте написання великих, монолітних API-маршрутів. Натомість розбивайте свій код на менші, багаторазово використовувані модулі. Це робить ваш код легшим для розуміння, тестування та підтримки.

2. Впроваджуйте обробку помилок

Належним чином обробляйте помилки у ваших API-маршрутах. Використовуйте блоки try...catch для перехоплення винятків та повернення відповідних відповідей про помилки клієнту. Логуйте помилки, щоб полегшити налагодження та моніторинг.

3. Валідуйте вхідні дані

Завжди валідуйте вхідні дані від клієнта, щоб запобігти вразливостям безпеки та забезпечити цілісність даних. Використовуйте бібліотеки валідації, такі як Joi або Yup, для визначення схем валідації та застосування обмежень на дані.

4. Захищайте конфіденційні дані

Зберігайте конфіденційні дані, такі як API-ключі та облікові дані бази даних, у змінних середовища. Ніколи не комітьте конфіденційні дані до свого репозиторію коду.

5. Впроваджуйте обмеження частоти запитів (Rate Limiting)

Захищайте свої API-маршрути від зловживань, впроваджуючи обмеження частоти запитів. Це обмежує кількість запитів, які клієнт може зробити за певний проміжок часу. Використовуйте бібліотеки для обмеження частоти запитів, такі як express-rate-limit або limiter.

6. Захищайте API-ключі

Не розкривайте API-ключі безпосередньо в коді на стороні клієнта. Завжди проксіюйте запити через ваші API-маршрути, щоб захистити свої API-ключі від несанкціонованого доступу. Зберігайте API-ключі надійно у змінних середовища на вашому сервері.

7. Використовуйте змінні середовища

Уникайте жорсткого кодування значень конфігурації у вашому коді. Натомість використовуйте змінні середовища для зберігання налаштувань конфігурації. Це полегшує керування вашим застосунком у різних середовищах (розробка, тестування, продакшн).

8. Логування та моніторинг

Впроваджуйте логування та моніторинг для відстеження продуктивності ваших API-маршрутів. Логуйте важливі події, такі як помилки, попередження та успішні запити. Використовуйте інструменти моніторингу для відстеження метрик, таких як затримка запитів, частота помилок та використання ресурсів. Можуть бути корисними такі сервіси, як Sentry, Datadog або New Relic.

Аспекти розгортання

API-маршрути Next.js розроблені для розгортання на безсерверних платформах. Популярні варіанти розгортання включають:

Під час розгортання вашого застосунку Next.js з API-маршрутами переконайтеся, що ваші змінні середовища належним чином налаштовані на платформі розгортання. Також враховуйте час холодного старту безсерверних функцій, який може вплинути на початковий час відповіді ваших API-маршрутів. Оптимізація коду та використання таких технік, як provisioned concurrency, можуть допомогти зменшити проблеми з холодним стартом.

Висновок

API-маршрути Next.js надають потужний та зручний спосіб створення повностекових застосунків за допомогою React. Використовуючи безсерверні функції, ви можете спростити розробку, зменшити операційні витрати та покращити продуктивність застосунку. Дотримуючись найкращих практик, викладених у цій статті, ви зможете створювати надійні та підтримувані API-маршрути, які будуть основою ваших застосунків Next.js.

Незалежно від того, чи створюєте ви просту контактну форму, чи складну платформу для електронної комерції, API-маршрути Next.js допоможуть вам оптимізувати процес розробки та забезпечити винятковий досвід користувача.

Додаткові матеріали для вивчення