Polski

Poznaj trasy API Next.js i odblokuj możliwości programowania full-stack w swoich aplikacjach React. Ucz się wzorców, najlepszych praktyk i strategii wdrażania.

Trasy API Next.js: Wzorce programowania Full-Stack

Next.js zrewolucjonizował tworzenie aplikacji React, zapewniając solidny framework do budowania wydajnych i skalowalnych aplikacji internetowych. Jedną z jego kluczowych cech są trasy API, które umożliwiają programistom tworzenie funkcjonalności backendu bezpośrednio w projektach Next.js. Takie podejście usprawnia proces tworzenia, upraszcza wdrażanie i odblokowuje potężne możliwości full-stack.

Co to są trasy API Next.js?

Trasy API Next.js to funkcje bezserwerowe pisane bezpośrednio w katalogu /pages/api. Każdy plik w tym katalogu staje się punktem końcowym API, automatycznie kierując żądania HTTP do odpowiadającej mu funkcji. Eliminuje to potrzebę oddzielnego serwera backendu, upraszczając architekturę aplikacji i redukując koszty operacyjne.

Pomyśl o nich jak o miniaturowych funkcjach bezserwerowych, które znajdują się w twojej aplikacji Next.js. Odpowiadają na żądania HTTP, takie jak GET, POST, PUT, DELETE i mogą wchodzić w interakcje z bazami danych, zewnętrznymi interfejsami API i innymi zasobami po stronie serwera. Co ważne, działają tylko na serwerze, a nie w przeglądarce użytkownika, zapewniając bezpieczeństwo poufnych danych, takich jak klucze API.

Kluczowe korzyści tras API

Rozpoczęcie pracy z trasami API

Tworzenie trasy API w Next.js jest proste. Po prostu utwórz nowy plik w katalogu /pages/api. Nazwa pliku określi ścieżkę trasy. Na przykład, utworzenie pliku o nazwie /pages/api/hello.js spowoduje utworzenie punktu końcowego API dostępnego pod adresem /api/hello.

Przykład: Prosty interfejs API powitania

Oto podstawowy przykład trasy API, która zwraca odpowiedź JSON:


// pages/api/hello.js

export default function handler(req, res) {
  res.status(200).json({ message: 'Witaj z trasy API Next.js!' });
}

Ten kod definiuje asynchroniczną funkcję handler, która otrzymuje dwa argumenty:

Funkcja ustawia kod statusu HTTP na 200 (OK) i zwraca odpowiedź JSON z komunikatem.

Obsługa różnych metod HTTP

Możesz obsługiwać różne metody HTTP (GET, POST, PUT, DELETE itp.) w swojej trasie API, sprawdzając właściwość req.method. Umożliwia to łatwe tworzenie interfejsów API RESTful.


// pages/api/todos.js

export default async function handler(req, res) {
  if (req.method === 'GET') {
    // Pobierz wszystkie zadania z bazy danych
    const todos = await fetchTodos();
    res.status(200).json(todos);
  } else if (req.method === 'POST') {
    // Utwórz nowe zadanie
    const newTodo = await createTodo(req.body);
    res.status(201).json(newTodo);
  } else {
    // Obsługa nieobsługiwanych metod
    res.status(405).json({ message: 'Metoda niedozwolona' });
  }
}

Ten przykład pokazuje, jak obsługiwać żądania GET i POST dla hipotetycznego punktu końcowego /api/todos. Zawiera również obsługę błędów dla nieobsługiwanych metod.

Wzorce programowania Full-Stack z trasami API

Trasy API Next.js umożliwiają różne wzorce programowania full-stack. Oto kilka typowych przypadków użycia:

1. Pobieranie i manipulowanie danymi

Trasy API mogą być używane do pobierania danych z baz danych, zewnętrznych interfejsów API lub innych źródeł danych. Można ich również używać do manipulowania danymi, np. tworzenia, aktualizacji lub usuwania rekordów.

Przykład: Pobieranie danych użytkownika z bazy danych


// 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: 'Użytkownik nie znaleziony' });
    }

    res.status(200).json(results[0]);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: 'Błąd wewnętrzny serwera' });
  }
}

Ten przykład pobiera dane użytkownika z bazy danych na podstawie identyfikatora użytkownika podanego w adresie URL. Używa biblioteki zapytań do bazy danych (zakłada się, że znajduje się w lib/db) do interakcji z bazą danych. Zwróć uwagę na użycie parametryzowanych zapytań, aby zapobiec lukom w zabezpieczeniach typu SQL injection.

2. Uwierzytelnianie i autoryzacja

Trasy API mogą być używane do implementacji logiki uwierzytelniania i autoryzacji. Możesz ich używać do weryfikacji danych uwierzytelniających użytkownika, generowania tokenów JWT i ochrony poufnych zasobów.

Przykład: Uwierzytelnianie użytkownika


// 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: 'Nieprawidłowe dane uwierzytelniające' });
      }

      const user = results[0];

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

      if (!passwordMatch) {
        return res.status(401).json({ message: 'Nieprawidłowe dane uwierzytelniające' });
      }

      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: 'Błąd wewnętrzny serwera' });
    }
  } else {
    res.status(405).json({ message: 'Metoda niedozwolona' });
  }
}

Ten przykład uwierzytelnia użytkowników, porównując podane hasło z przechowywanym hasłem zhaszowanym w bazie danych. Jeśli dane uwierzytelniające są prawidłowe, generuje token JWT i zwraca go do klienta. Klient może następnie użyć tego tokena do uwierzytelniania kolejnych żądań.

3. Obsługa formularzy i przesyłanie danych

Trasy API mogą być używane do obsługi przesyłania formularzy i przetwarzania danych wysyłanych od klienta. Jest to przydatne do tworzenia formularzy kontaktowych, formularzy rejestracyjnych i innych elementów interaktywnych.

Przykład: Przesyłanie formularza kontaktowego


// 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: 'Nowe zgłoszenie z formularza kontaktowego',
        text: `Imię: ${name}\nEmail: ${email}\nWiadomość: ${message}`,
      });

      res.status(200).json({ message: 'E-mail wysłany pomyślnie' });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Nie udało się wysłać e-maila' });
    }
  } else {
    res.status(405).json({ message: 'Metoda niedozwolona' });
  }
}

Ten przykład obsługuje zgłoszenie formularza kontaktowego, wysyłając e-mail do administratora. Używa biblioteki wysyłania e-maili (zakłada się, że znajduje się w lib/email), aby wysłać e-mail. Powinieneś zastąpić admin@example.com rzeczywistym adresem e-mail odbiorcy.

4. Webhooki i obsługa zdarzeń

Trasy API mogą być używane do obsługi webhooków i reagowania na zdarzenia z usług zewnętrznych. Umożliwia to integrację aplikacji Next.js z innymi platformami i automatyzację zadań.

Przykład: Obsługa webhooka 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, // Wyłącz domyślne parsowanie treści
  },
};

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(`Błąd webhooka: ${err.message}`);
      res.status(400).send(`Błąd webhooka: ${err.message}`);
      return;
    }

    // Obsługa zdarzenia
    switch (event.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = event.data.object;
        console.log(`PaymentIntent dla ${paymentIntent.amount} zakończony sukcesem!`);
        // Następnie zdefiniuj i wywołaj metodę obsługującą pomyślne uruchomienie payment intent.
        // handlePaymentIntentSucceeded(paymentIntent);
        break;
      case 'payment_method.attached':
        const paymentMethod = event.data.object;
        // Następnie zdefiniuj i wywołaj metodę obsługującą pomyślne dołączenie PaymentMethod.
        // handlePaymentMethodAttached(paymentMethod);
        break;
      default:
        // Niespodziewany typ zdarzenia
        console.log(`Nierozpoznany typ zdarzenia ${event.type}.`);
    }

    // Zwróć odpowiedź 200, aby potwierdzić odbiór zdarzenia
    res.status(200).json({ received: true });
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Metoda niedozwolona');
  }
}

Ten przykład obsługuje webhooka Stripe, weryfikując podpis i przetwarzając dane zdarzenia. Wyłącza domyślny parser treści i używa niestandardowej funkcji bufora do odczytu nieprzetworzonej treści żądania. Konieczne jest wyłączenie domyślnego parsera treści, ponieważ Stripe wymaga nieprzetworzonej treści do weryfikacji podpisu. Pamiętaj, aby skonfigurować punkt końcowy webhooka Stripe w swoim panelu Stripe i ustawić zmienną środowiskową STRIPE_WEBHOOK_SECRET.

Najlepsze praktyki dotyczące tras API

Aby zapewnić jakość i łatwość konserwacji tras API, przestrzegaj następujących najlepszych praktyk:

1. Modularizuj swój kod

Unikaj pisania dużych, monolitowych tras API. Zamiast tego podziel swój kod na mniejsze, wielokrotnego użytku moduły. Ułatwia to zrozumienie, testowanie i konserwację kodu.

2. Implementacja obsługi błędów

Prawidłowo obsługuj błędy w swoich trasach API. Użyj bloków try...catch do przechwytywania wyjątków i zwracania odpowiednich odpowiedzi o błędach do klienta. Rejestruj błędy, aby ułatwić debugowanie i monitorowanie.

3. Walidacja danych wejściowych

Zawsze sprawdzaj poprawność danych wejściowych od klienta, aby zapobiec lukom w zabezpieczeniach i zapewnić integralność danych. Użyj bibliotek walidacji, takich jak Joi lub Yup, aby zdefiniować schematy walidacji i wymusić ograniczenia danych.

4. Chroń poufne dane

Przechowuj poufne dane, takie jak klucze API i dane uwierzytelniające bazy danych, w zmiennych środowiskowych. Nigdy nie zatwierdzaj poufnych danych do repozytorium kodu.

5. Implementacja ograniczania liczby żądań

Chroń swoje trasy API przed nadużyciami, implementując ograniczanie liczby żądań. Ogranicza to liczbę żądań, które klient może wykonać w danym okresie czasu. Użyj bibliotek ograniczania liczby żądań, takich jak express-rate-limit lub limiter.

6. Zabezpiecz klucze API

Nie ujawniaj kluczy API bezpośrednio w kodzie po stronie klienta. Zawsze kieruj żądania przez swoje trasy API, aby chronić swoje klucze API przed nieautoryzowanym dostępem. Przechowuj klucze API bezpiecznie w zmiennych środowiskowych na swoim serwerze.

7. Użyj zmiennych środowiskowych

Unikaj kodowania na stałe wartości konfiguracji w swoim kodzie. Zamiast tego użyj zmiennych środowiskowych do przechowywania ustawień konfiguracji. Ułatwia to zarządzanie aplikacją w różnych środowiskach (tworzenie, etap, produkcja).

8. Rejestrowanie i monitorowanie

Zaimplementuj rejestrowanie i monitorowanie, aby śledzić wydajność swoich tras API. Rejestruj ważne zdarzenia, takie jak błędy, ostrzeżenia i pomyślne żądania. Użyj narzędzi monitorowania, aby śledzić metryki, takie jak opóźnienie żądań, wskaźniki błędów i wykorzystanie zasobów. Pomocne mogą być usługi takie jak Sentry, Datadog lub New Relic.

Kwestie dotyczące wdrażania

Trasy API Next.js są przeznaczone do wdrażania na platformach bezserwerowych. Popularne opcje wdrażania obejmują:

Podczas wdrażania aplikacji Next.js z trasami API upewnij się, że zmienne środowiskowe są poprawnie skonfigurowane na platformie wdrażania. Rozważ również czas zimnego startu funkcji bezserwerowych, który może mieć wpływ na początkowy czas odpowiedzi tras API. Optymalizacja kodu i stosowanie technik, takich jak udostępniona współbieżność, mogą pomóc w ograniczeniu problemów z zimnym startem.

Wnioski

Trasy API Next.js zapewniają potężny i wygodny sposób budowania aplikacji full-stack z React. Wykorzystując funkcje bezserwerowe, możesz uprościć tworzenie, zmniejszyć koszty operacyjne i poprawić wydajność aplikacji. Postępując zgodnie z najlepszymi praktykami opisanymi w tym artykule, możesz tworzyć niezawodne i łatwe w utrzymaniu trasy API, które zasilają Twoje aplikacje Next.js.

Niezależnie od tego, czy budujesz prosty formularz kontaktowy, czy złożoną platformę e-commerce, trasy API Next.js mogą pomóc w usprawnieniu procesu tworzenia i zapewnieniu wyjątkowych wrażeń użytkownika.

Dalsza nauka