Deutsch

Entdecken Sie Next.js API Routes und nutzen Sie die Full-Stack-Entwicklungsfunktionen in Ihren React-Anwendungen. Lernen Sie Muster, Best Practices und Bereitstellungsstrategien kennen.

Next.js API Routes: Full-Stack-Entwicklungsmuster

Next.js hat die React-Entwicklung revolutioniert, indem es ein robustes Framework für den Aufbau leistungsstarker und skalierbarer Webanwendungen bereitstellt. Eine seiner Schlüsselfunktionen sind API Routes, die es Entwicklern ermöglichen, Backend-Funktionalität direkt in ihren Next.js-Projekten zu erstellen. Dieser Ansatz rationalisiert die Entwicklung, vereinfacht die Bereitstellung und erschließt leistungsstarke Full-Stack-Fähigkeiten.

Was sind Next.js API Routes?

Next.js API Routes sind serverlose Funktionen, die direkt in Ihrem /pages/api-Verzeichnis geschrieben werden. Jede Datei in diesem Verzeichnis wird zu einem API-Endpunkt, der HTTP-Anfragen automatisch an seine entsprechende Funktion weiterleitet. Dies eliminiert die Notwendigkeit eines separaten Backend-Servers, vereinfacht Ihre Anwendungsarchitektur und reduziert den Betriebsaufwand.

Stellen Sie sie sich als Miniatur-Serverless-Funktionen vor, die in Ihrer Next.js-Anwendung leben. Sie reagieren auf HTTP-Anfragen wie GET, POST, PUT, DELETE und können mit Datenbanken, externen APIs und anderen serverseitigen Ressourcen interagieren. Entscheidend ist, dass sie nur auf dem Server laufen, nicht im Browser des Benutzers, was die Sicherheit sensibler Daten wie API-Schlüssel gewährleistet.

Hauptvorteile von API Routes

Erste Schritte mit API Routes

Das Erstellen einer API-Route in Next.js ist unkompliziert. Erstellen Sie einfach eine neue Datei im Verzeichnis /pages/api. Der Dateiname bestimmt den Pfad der Route. Wenn Sie beispielsweise eine Datei namens /pages/api/hello.js erstellen, wird ein API-Endpunkt unter /api/hello zugänglich.

Beispiel: Eine einfache Begrüßungs-API

Hier ist ein einfaches Beispiel für eine API-Route, die eine JSON-Antwort zurückgibt:


// pages/api/hello.js

export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Next.js API Route!' });
}

Dieser Code definiert eine asynchrone Funktion handler, die zwei Argumente empfängt:

Die Funktion setzt den HTTP-Statuscode auf 200 (OK) und gibt eine JSON-Antwort mit einer Nachricht zurück.

Umgang mit verschiedenen HTTP-Methoden

Sie können verschiedene HTTP-Methoden (GET, POST, PUT, DELETE usw.) innerhalb Ihrer API-Route behandeln, indem Sie die Eigenschaft req.method überprüfen. Dies ermöglicht Ihnen die einfache Erstellung von RESTful APIs.


// pages/api/todos.js

export default async function handler(req, res) {
  if (req.method === 'GET') {
    // Alle Todos aus der Datenbank abrufen
    const todos = await fetchTodos();
    res.status(200).json(todos);
  } else if (req.method === 'POST') {
    // Ein neues Todo erstellen
    const newTodo = await createTodo(req.body);
    res.status(201).json(newTodo);
  } else {
    // Nicht unterstützte Methoden behandeln
    res.status(405).json({ message: 'Method Not Allowed' });
  }
}

Dieses Beispiel demonstriert, wie GET- und POST-Anfragen für einen hypothetischen /api/todos-Endpunkt behandelt werden. Es beinhaltet auch eine Fehlerbehandlung für nicht unterstützte Methoden.

Full-Stack-Entwicklungsmuster mit API Routes

Next.js API Routes ermöglichen verschiedene Full-Stack-Entwicklungsmuster. Hier sind einige gängige Anwendungsfälle:

1. Datenabruf und -manipulation

API Routes können verwendet werden, um Daten aus Datenbanken, externen APIs oder anderen Datenquellen abzurufen. Sie können auch zur Manipulation von Daten verwendet werden, z. B. zum Erstellen, Aktualisieren oder Löschen von Datensätzen.

Beispiel: Abrufen von Benutzerdaten aus einer Datenbank


// 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: 'User not found' });
    }

    res.status(200).json(results[0]);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: 'Internal Server Error' });
  }
}

Dieses Beispiel ruft Benutzerdaten aus einer Datenbank ab, basierend auf der in der URL bereitgestellten Benutzer-ID. Es verwendet eine Datenbankabfragebibliothek (angenommen in lib/db), um mit der Datenbank zu interagieren. Beachten Sie die Verwendung von parametrisierten Abfragen, um SQL-Injection-Schwachstellen zu verhindern.

2. Authentifizierung und Autorisierung

API Routes können zur Implementierung von Authentifizierungs- und Autorisierungslogik verwendet werden. Sie können damit Benutzeranmeldeinformationen überprüfen, JWT-Tokens generieren und sensible Ressourcen schützen.

Beispiel: Benutzerauthentifizierung


// 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: 'Invalid credentials' });
      }

      const user = results[0];

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

      if (!passwordMatch) {
        return res.status(401).json({ message: 'Invalid credentials' });
      }

      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: 'Internal Server Error' });
    }
  } else {
    res.status(405).json({ message: 'Method Not Allowed' });
  }
}

Dieses Beispiel authentifiziert Benutzer, indem es das angegebene Passwort mit dem in der Datenbank gespeicherten gehashten Passwort vergleicht. Sind die Anmeldeinformationen gültig, wird ein JWT-Token generiert und an den Client zurückgegeben. Der Client kann dieses Token dann zur Authentifizierung nachfolgender Anfragen.

3. Formularverarbeitung und Datenübermittlung

API Routes können verwendet werden, um Formularübermittlungen zu verarbeiten und vom Client gesendete Daten zu verarbeiten. Dies ist nützlich für die Erstellung von Kontaktformularen, Registrierungsformularen und anderen interaktiven Elementen.

Beispiel: Übermittlung eines Kontaktformulars


// 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: 'Neue Kontaktformular-Einreichung',
        text: `Name: ${name}\\nEmail: ${email}\\nMessage: ${message}`,
      });

      res.status(200).json({ message: 'E-Mail erfolgreich gesendet' });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'E-Mail konnte nicht gesendet werden' });
    }
  } else {
    res.status(405).json({ message: 'Method Not Allowed' });
  }
}

Dieses Beispiel verarbeitet eine Kontaktformularübermittlung, indem es eine E-Mail an den Administrator sendet. Es verwendet eine E-Mail-Versandbibliothek (angenommen in lib/email), um die E-Mail zu versenden. Sie sollten admin@example.com durch die tatsächliche Empfänger-E-Mail-Adresse ersetzen.

4. Webhooks und Ereignisbehandlung

API Routes können verwendet werden, um Webhooks zu verarbeiten und auf Ereignisse von externen Diensten zu reagieren. Dies ermöglicht Ihnen die Integration Ihrer Next.js-Anwendung mit anderen Plattformen und die Automatisierung von Aufgaben.

Beispiel: Handhabung eines Stripe Webhooks


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

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

export const config = {
  api: {
    bodyParser: false, // Standard-Body-Parsing deaktivieren
  },
};

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(`Webhook Error: ${err.message}`);
      res.status(400).send(`Webhook Error: ${err.message}`);
      return;
    }

    // Das Ereignis verarbeiten
    switch (event.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = event.data.object;
        console.log(`PaymentIntent für ${paymentIntent.amount} war erfolgreich!`);
        // Dann eine Methode definieren und aufrufen, um den erfolgreichen Payment Intent zu verarbeiten.
        // handlePaymentIntentSucceeded(paymentIntent);
        break;
      case 'payment_method.attached':
        const paymentMethod = event.data.object;
        // Dann eine Methode definieren und aufrufen, um die erfolgreiche Anbindung einer PaymentMethod zu verarbeiten.
        // handlePaymentMethodAttached(paymentMethod);
        break;
      default:
        // Unerwarteter Ereignistyp
        console.log(`Unbehandelter Ereignistyp ${event.type}.`);
    }

    // Eine 200-Antwort zurückgeben, um den Empfang des Ereignisses zu bestätigen
    res.status(200).json({ received: true });
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Methode nicht erlaubt');
  }
}

Dieses Beispiel verarbeitet einen Stripe-Webhook, indem es die Signatur verifiziert und die Ereignisdaten verarbeitet. Es deaktiviert den Standard-Body-Parser und verwendet eine benutzerdefinierte Pufferfunktion, um den rohen Anforderungs-Body zu lesen. Es ist entscheidend, den Standard-Body-Parser zu deaktivieren, da Stripe den rohen Body für die Signaturverifizierung benötigt. Denken Sie daran, Ihren Stripe-Webhook-Endpunkt in Ihrem Stripe-Dashboard zu konfigurieren und die Umgebungsvariable STRIPE_WEBHOOK_SECRET festzulegen.

Best Practices für API Routes

Um die Qualität und Wartbarkeit Ihrer API Routes zu gewährleisten, befolgen Sie diese Best Practices:

1. Modularisieren Sie Ihren Code

Vermeiden Sie das Schreiben großer, monolithischer API-Routen. Unterteilen Sie Ihren Code stattdessen in kleinere, wiederverwendbare Module. Dies macht Ihren Code leichter verständlich, testbar und wartbar.

2. Fehlerbehandlung implementieren

Behandeln Sie Fehler in Ihren API-Routen korrekt. Verwenden Sie try...catch-Blöcke, um Ausnahmen abzufangen und entsprechende Fehlerantworten an den Client zurückzugeben. Protokollieren Sie Fehler, um die Fehlerbehebung und Überwachung zu erleichtern.

3. Eingabedaten validieren

Validieren Sie immer die Eingabedaten vom Client, um Sicherheitslücken zu vermeiden und die Datenintegrität zu gewährleisten. Verwenden Sie Validierungsbibliotheken wie Joi oder Yup, um Validierungsschemata zu definieren und Datenbeschränkungen durchzusetzen.

4. Sensible Daten schützen

Speichern Sie sensible Daten, wie API-Schlüssel und Datenbankzugangsdaten, in Umgebungsvariablen. Committen Sie niemals sensible Daten in Ihr Code-Repository.

5. Ratenbegrenzung implementieren

Schützen Sie Ihre API-Routen vor Missbrauch, indem Sie eine Ratenbegrenzung implementieren. Dies begrenzt die Anzahl der Anfragen, die ein Client innerhalb eines bestimmten Zeitraums stellen kann. Verwenden Sie Ratenbegrenzungsbibliotheken wie express-rate-limit oder limiter.

6. API-Schlüssel sichern

Geben Sie API-Schlüssel nicht direkt im clientseitigen Code preis. Leiten Sie Anfragen immer über Ihre API-Routen weiter, um Ihre API-Schlüssel vor unbefugtem Zugriff zu schützen. Speichern Sie API-Schlüssel sicher in Umgebungsvariablen auf Ihrem Server.

7. Umgebungsvariablen verwenden

Vermeiden Sie es, Konfigurationswerte in Ihrem Code fest zu codieren. Verwenden Sie stattdessen Umgebungsvariablen, um Konfigurationseinstellungen zu speichern. Dies erleichtert die Verwaltung Ihrer Anwendung in verschiedenen Umgebungen (Entwicklung, Staging, Produktion).

8. Protokollierung und Überwachung

Implementieren Sie Protokollierung und Überwachung, um die Leistung Ihrer API-Routen zu verfolgen. Protokollieren Sie wichtige Ereignisse wie Fehler, Warnungen und erfolgreiche Anfragen. Verwenden Sie Überwachungstools, um Metriken wie Anfragelatenz, Fehlerraten und Ressourcennutzung zu verfolgen. Dienste wie Sentry, Datadog oder New Relic können hilfreich sein.

Bereitstellungsüberlegungen

Next.js API Routes sind für die Bereitstellung auf serverlosen Plattformen konzipiert. Beliebte Bereitstellungsoptionen sind:

Stellen Sie bei der Bereitstellung Ihrer Next.js-Anwendung mit API Routes sicher, dass Ihre Umgebungsvariablen auf der Bereitstellungsplattform ordnungsgemäß konfiguriert sind. Berücksichtigen Sie auch die Kaltstartzeit von serverlosen Funktionen, die die anfängliche Antwortzeit Ihrer API-Routen beeinflussen kann. Das Optimieren Ihres Codes und die Verwendung von Techniken wie bereitgestellter Parallelität (provisioned concurrency) können dazu beitragen, Kaltstartprobleme zu mildern.

Fazit

Next.js API Routes bieten eine leistungsstarke und bequeme Möglichkeit, Full-Stack-Anwendungen mit React zu erstellen. Durch die Nutzung serverloser Funktionen können Sie die Entwicklung vereinfachen, den Betriebsaufwand reduzieren und die Anwendungsleistung verbessern. Indem Sie die in diesem Artikel beschriebenen Best Practices befolgen, können Sie robuste und wartbare API Routes erstellen, die Ihre Next.js-Anwendungen antreiben.

Egal, ob Sie ein einfaches Kontaktformular oder eine komplexe E-Commerce-Plattform erstellen, Next.js API Routes können Ihnen dabei helfen, Ihren Entwicklungsprozess zu optimieren und außergewöhnliche Benutzererfahrungen zu liefern.

Weiterführende Informationen