Polski

Dowiedz się, jak wykorzystać Trasy API Next.js do budowy backendów bezserwerowych. Przewodnik omawia konfigurację, uwierzytelnianie, utrwalanie danych i inne zaawansowane techniki.

Trasy API Next.js: Zbuduj Swój Backend z Łatwością

Next.js zrewolucjonizował rozwój front-endu dzięki swoim potężnym funkcjom i intuicyjnej strukturze. Ale czy wiesz, że może również znacznie uprościć tworzenie backendu? Trasy API Next.js (API Routes) pozwalają tworzyć bezserwerowe punkty końcowe API bezpośrednio w aplikacji Next.js, w wielu przypadkach eliminując potrzebę posiadania oddzielnego serwera backendowego. Ten kompleksowy przewodnik przeprowadzi Cię przez proces budowania solidnego i skalowalnego backendu przy użyciu Tras API Next.js.

Czym są Trasy API Next.js?

Trasy API to funkcje bezserwerowe, które tworzysz w katalogu /pages/api w swoim projekcie Next.js. Funkcje te obsługują przychodzące żądania HTTP i zwracają odpowiedzi, podobnie jak tradycyjne API backendowe. Kluczowa różnica polega na tym, że są one wdrażane jako funkcje bezserwerowe, co oznacza, że nie musisz zarządzać serwerami ani infrastrukturą.

Pomyśl o nich jak o lekkich, uruchamianych na żądanie funkcjach backendowych, które są płynnie zintegrowane z Twoim front-endem Next.js.

Korzyści z używania Tras API Next.js

Pierwsze kroki z Trasami API Next.js

Stwórzmy prostą trasę API, która zwraca odpowiedź w formacie JSON. Najpierw upewnij się, że masz skonfigurowany projekt Next.js. Jeśli nie, utwórz go za pomocą:

npx create-next-app my-app
cd my-app

Teraz utwórz plik o nazwie hello.js w katalogu /pages/api:

// plik: pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ name: 'Jan Kowalski' })
}

Ten kod definiuje prostą trasę API, która odpowiada obiektem JSON zawierającym imię "Jan Kowalski". Aby uzyskać dostęp do tej trasy API, uruchom serwer deweloperski Next.js:

npm run dev

Następnie otwórz przeglądarkę i przejdź do http://localhost:3000/api/hello. Powinieneś zobaczyć następującą odpowiedź JSON:

{"name": "Jan Kowalski"}

Zrozumienie funkcji obsługującej trasę API (handler)

Funkcja handler w Twojej trasie API otrzymuje dwa argumenty:

Możesz używać tych obiektów do obsługi różnych typów żądań, odczytywania danych z treści żądania, ustawiania nagłówków odpowiedzi i wysyłania różnych typów odpowiedzi.

Obsługa różnych metod HTTP

Możesz użyć właściwości req.method, aby określić metodę HTTP przychodzącego żądania i odpowiednio obsłużyć różne metody. Na przykład:

// plik: pages/api/method.js
export default function handler(req, res) {
  if (req.method === 'GET') {
    // Obsłuż żądanie GET
    res.status(200).json({ message: 'To jest żądanie GET' })
  } else if (req.method === 'POST') {
    // Obsłuż żądanie POST
    res.status(200).json({ message: 'To jest żądanie POST' })
  } else {
    // Obsłuż inne metody
    res.status(405).json({ message: 'Metoda niedozwolona' })
  }
}

W tym przykładzie trasa API obsługuje zarówno żądania GET, jak i POST. Jeśli metoda żądania to GET, odpowiada obiektem JSON zawierającym komunikat "To jest żądanie GET". Jeśli metoda żądania to POST, odpowiada obiektem JSON zawierającym komunikat "To jest żądanie POST". Jeśli metoda żądania jest inna, odpowiada błędem 405 Method Not Allowed (Metoda niedozwolona).

Odczytywanie danych z treści żądania

Dla żądań POST, PUT i PATCH często trzeba odczytać dane z treści żądania. Next.js zapewnia wbudowane wsparcie dla parsowania treści żądań w formacie JSON i URL-encoded. Aby sparsować treść żądania JSON, możesz użyć właściwości req.body. Na przykład:

// plik: pages/api/post.js
export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email } = req.body

    // Przetwórz dane
    console.log('Imię:', name)
    console.log('Email:', email)

    res.status(200).json({ message: 'Dane otrzymane pomyślnie' })
  } else {
    res.status(405).json({ message: 'Metoda niedozwolona' })
  }
}

Aby przetestować tę trasę API, możesz użyć narzędzia takiego jak Postman lub curl do wysłania żądania POST z treścią JSON:

curl -X POST -H "Content-Type: application/json" -d '{"name": "Anna Nowak", "email": "anna.nowak@example.com"}' http://localhost:3000/api/post

Ustawianie nagłówków odpowiedzi

Możesz użyć metody res.setHeader(), aby ustawić nagłówki odpowiedzi. Jest to przydatne do ustawiania typu zawartości, kontroli pamięci podręcznej (cache control) i innych ważnych informacji. Na przykład:

// plik: pages/api/headers.js
export default function handler(req, res) {
  res.setHeader('Content-Type', 'application/json')
  res.setHeader('Cache-Control', 's-maxage=3600')
  res.status(200).json({ message: 'Witaj, świecie!' })
}

W tym przykładzie trasa API ustawia nagłówek Content-Type na application/json, wskazując, że odpowiedź jest obiektem JSON. Ustawia również nagłówek Cache-Control na s-maxage=3600, co informuje przeglądarkę i CDN, aby przechowywały odpowiedź w pamięci podręcznej przez maksymalnie 1 godzinę.

Obsługa błędów

Ważne jest, aby elegancko obsługiwać błędy w trasach API. Możesz używać bloków try-catch do przechwytywania wyjątków i wysyłania odpowiednich odpowiedzi o błędach do klienta. Na przykład:

// plik: pages/api/error.js
export default async function handler(req, res) {
  try {
    // Symuluj błąd
    throw new Error('Coś poszło nie tak')
  } catch (error) {
    console.error(error)
    res.status(500).json({ message: 'Wewnętrzny błąd serwera' })
  }
}

W tym przykładzie trasa API symuluje błąd, rzucając nowy obiekt Error. Blok catch przechwytuje błąd, loguje go do konsoli i wysyła do klienta odpowiedź 500 Internal Server Error (Wewnętrzny błąd serwera). Rozważ użycie solidnego systemu logowania, takiego jak Sentry lub Datadog, w środowiskach produkcyjnych.

Łączenie z bazą danych

Jednym z najczęstszych przypadków użycia tras API jest łączenie się z bazą danych. Trasy API Next.js płynnie integrują się z różnymi bazami danych, w tym:

Oto przykład, jak połączyć się z bazą danych MongoDB w trasie API Next.js:

// plik: pages/api/mongodb.js
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {}

let client
let clientPromise

if (!process.env.MONGODB_URI) {
  throw new Error('Dodaj swój URI do Mongo w pliku .env.local')
}

if (process.env.NODE_ENV === 'development') {
  // W trybie deweloperskim użyj zmiennej globalnej, aby wartość
  // była zachowywana między przeładowaniami modułów spowodowanymi przez HMR (Hot Module Replacement).
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options)
    global._mongoClientPromise = client.connect()
  }
  clientPromise = global._mongoClientPromise
} else {
  // W trybie produkcyjnym najlepiej nie używać zmiennej globalnej.
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

// Eksportuj obietnicę MongoClient o zasięgu modułu. Robiąc to w
// osobnym module, klient może być bezpiecznie ponownie używany w wielu
// funkcjach. Zobacz: https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js
export default async function handler(req, res) {
  try {
    const client = await clientPromise
    const db = client.db(process.env.MONGODB_DB)
    const collection = db.collection('users')

    const users = await collection.find({}).toArray()

    res.status(200).json({ users })
  } catch (e) {
    console.error(e)
    res.status(500).json({ message: 'Nie udało się pobrać użytkowników' })
  }
}

Przed uruchomieniem tego kodu upewnij się, że masz zainstalowany pakiet mongodb:

npm install mongodb

Musisz również ustawić zmienne środowiskowe MONGODB_URI i MONGODB_DB. Zmienne te powinny być zdefiniowane w pliku .env.local (lub w ustawieniach zmiennych środowiskowych Twojego dostawcy hostingu dla środowiska produkcyjnego). MONGODB_URI zawiera ciąg połączenia do Twojej bazy danych MongoDB, a MONGODB_DB określa nazwę bazy danych.

Uwierzytelnianie i autoryzacja

Ochrona tras API jest kluczowa dla bezpieczeństwa. Trasy API Next.js mogą być zabezpieczone przy użyciu różnych technik uwierzytelniania i autoryzacji, w tym:

Oto przykład, jak zabezpieczyć trasę API za pomocą uwierzytelniania JWT:

// plik: pages/api/protected.js
import jwt from 'jsonwebtoken'

const secret = process.env.JWT_SECRET

export default function handler(req, res) {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    return res.status(401).json({ message: 'Brak autoryzacji' })
  }

  try {
    const decoded = jwt.verify(token, secret)
    // Obiekt "decoded" zawiera informacje o użytkowniku osadzone w tokenie
    // Na przykład: const userId = decoded.userId;

    // Kontynuuj przetwarzanie żądania
    res.status(200).json({ message: 'Dostęp do chronionego zasobu uzyskany pomyślnie' })
  } catch (error) {
    return res.status(401).json({ message: 'Nieprawidłowy token' })
  }
}

Przed uruchomieniem tego kodu upewnij się, że masz zainstalowany pakiet jsonwebtoken:

npm install jsonwebtoken

Musisz również ustawić zmienną środowiskową JWT_SECRET. Powinien to być silny, losowo wygenerowany klucz tajny, używany do podpisywania i weryfikacji tokenów JWT. Przechowuj go bezpiecznie i nigdy nie ujawniaj w kodzie po stronie klienta.

Middleware

Chociaż Next.js nie oferuje tradycyjnego middleware dla tras API w taki sam sposób jak Express.js, można osiągnąć podobną funkcjonalność, opakowując funkcje obsługujące trasy API w funkcje wielokrotnego użytku. Pozwala to na wykonywanie zadań takich jak:

Oto przykład, jak stworzyć proste middleware do logowania:

// plik: utils/middleware.js
export function withLogging(handler) {
  return async function(req, res) {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`)
    return handler(req, res)
  }
}

Aby użyć tego middleware, po prostu opakuj swoją funkcję obsługującą trasę API funkcją withLogging:

// plik: pages/api/logged.js
import { withLogging } from '../../utils/middleware'

async function handler(req, res) {
  res.status(200).json({ message: 'To żądanie zostało zarejestrowane' })
}

export default withLogging(handler)

Dobre praktyki budowania tras API w Next.js

Zaawansowane techniki

Zadania w tle (Background Jobs)

W przypadku długotrwałych zadań, które nie powinny blokować odpowiedzi API, rozważ użycie zadań w tle. Możesz użyć bibliotek takich jak BullMQ lub Bree do zarządzania zadaniami w tle i przetwarzania ich asynchronicznie.

WebSockets

Dla aplikacji czasu rzeczywistego możesz używać WebSockets w swoich trasach API Next.js. Biblioteki takie jak Socket.IO i ws ułatwiają ustanawianie trwałych połączeń między klientem a serwerem.

GraphQL

Jeśli potrzebujesz bardziej elastycznego i wydajnego sposobu na pobieranie danych, rozważ użycie GraphQL. Możesz użyć bibliotek takich jak Apollo Server lub Yoga, aby utworzyć punkt końcowy API GraphQL w swojej aplikacji Next.js.

Podsumowanie

Trasy API Next.js zapewniają potężny i wygodny sposób na budowanie bezserwerowych backendów bezpośrednio w aplikacji Next.js. Wykorzystując zalety architektury bezserwerowej, możesz uprościć rozwój, poprawić wydajność i obniżyć koszty. Niezależnie od tego, czy budujesz prosty formularz kontaktowy, czy złożoną platformę e-commerce, trasy API Next.js mogą pomóc Ci z łatwością stworzyć solidny i skalowalny backend. Dzięki solidnemu zrozumieniu podstaw i stosowaniu dobrych praktyk możesz wykorzystać to potężne narzędzie do tworzenia wydajnych, bezpiecznych i globalnie dostępnych aplikacji.