Skip to content

REST API Tutorial 2026 – Node.js und Express

REST API Tutorial 2026: Kompletter Guide zum Bauen einer REST API mit Node.js und Express. CRUD-Operationen, Middleware, Authentifizierung und Deployment.

Einleitung

REST APIs sind das Rueckgrat moderner Web-Applikationen. Jede App die du nutzt – Instagram, Spotify, ChatGPT – kommuniziert ueber REST APIs. In diesem Tutorial baust du eine komplette REST API mit Node.js, Express und TypeScript.


Inhaltsverzeichnis

  1. Was ist eine REST API?
  2. Projekt-Setup
  3. Erste Route erstellen
  4. CRUD-Operationen
  5. Middleware
  6. Eingabe-Validierung
  7. Datenbank anbinden
  8. Authentifizierung mit JWT
  9. Error Handling
  10. Deployment

1. Was ist eine REST API?

Allerdings gibt es einige wichtige Unterschiede zu beachten.

REST (Representational State Transfer) ist ein Architekturstil fuer Web-APIs. Die Grundprinzipien:

  • Ressourcen: Alles ist eine Ressource (User, Produkte, Bestellungen)
  • HTTP-Methoden: GET (lesen), POST (erstellen), PUT (aktualisieren), DELETE (loeschen)
  • Stateless: Jede Anfrage enthaelt alle noetigen Informationen
  • JSON: Standard-Datenformat fuer Request und Response

HTTP-Methoden und CRUD

Grundsätzlich gibt es dabei einige Punkte zu beachten.

HTTP MethodeCRUDBeispielBeschreibung
GETReadGET /api/usersAlle User abrufen
GETReadGET /api/users/1User mit ID 1 abrufen
POSTCreatePOST /api/usersNeuen User erstellen
PUTUpdatePUT /api/users/1User 1 aktualisieren
DELETEDeleteDELETE /api/users/1User 1 loeschen

2. Projekt-Setup

Dennoch solltest du einige Besonderheiten beachten.

# Neues Projekt erstellen
mkdir rest-api-tutorial
cd rest-api-tutorial
npm init -y

# Dependencies installieren
npm install express cors dotenv
npm install -D typescript @types/express @types/cors @types/node ts-node nodemon

# TypeScript konfigurieren
npx tsc --init

Dementsprechend ist eine manuelle Überprüfung empfehlenswert.

Projekt-Struktur

Somit kannst du direkt mit der Umsetzung beginnen.

rest-api-tutorial/
├── src/
│   ├── index.ts          # Entry Point
│   ├── routes/
│   │   └── users.ts      # User Routes
│   ├── middleware/
│   │   ├── auth.ts       # Auth Middleware
│   │   └── validate.ts   # Validation
│   ├── controllers/
│   │   └── users.ts      # User Controller
│   └── types/
│       └── index.ts      # TypeScript Types
├── package.json
├── tsconfig.json
└── .env

Folglich erhältst du mit diesem Ansatz deutlich bessere Resultate.

package.json Scripts

Folglich profitierst du von einem besseren Verständnis dieser Konzepte.

{
  "scripts": {
    "dev": "nodemon --exec ts-node src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

Ebenfalls sinnvoll ist es, verschiedene Varianten auszuprobieren.


3. Erste Route erstellen

Ebenfalls relevant sind die praktischen Anwendungsbeispiele.

// src/index.ts
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(express.json());

// Health Check
app.get('/api/health', (req, res) => {
  res.json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    version: '1.0.0'
  });
});

// Server starten
app.listen(PORT, () => {
  console.log(`🚀 Server laeuft auf http://localhost:${PORT}`);
});
# Starten
npm run dev

# Testen (in neuem Terminal)
curl http://localhost:3000/api/health

Grundsätzlich kannst du diesen Prompt an deine Bedürfnisse anpassen.


4. CRUD-Operationen implementieren

Types definieren

Deshalb lohnt es sich, dieses Thema genauer zu betrachten.

// src/types/index.ts
export interface User {
  id: number;
  name: string;
  email: string;
  rolle: 'admin' | 'user';
  erstelltAm: Date;
}

export type NeuerUser = Omit<User, 'id' | 'erstelltAm'>;
export type UserUpdate = Partial<NeuerUser>;

Im Grunde funktioniert dieser Ansatz mit allen gängigen AI-Tools.

Controller erstellen

Natürlich gibt es dabei verschiedene Herangehensweisen.

// src/controllers/users.ts
import { Request, Response } from 'express';
import { User, NeuerUser, UserUpdate } from '../types';

// In-Memory Datenbank (spaeter durch echte DB ersetzen)
let users: User[] = [
  { id: 1, name: "Metin", email: "metin@example.de", rolle: "admin", erstelltAm: new Date() },
  { id: 2, name: "Anna", email: "anna@example.de", rolle: "user", erstelltAm: new Date() },
];
let nextId = 3;

// GET /api/users – Alle User abrufen
export const getUsers = (req: Request, res: Response) => {
  res.json({
    data: users,
    total: users.length
  });
};

// GET /api/users/:id – Einzelnen User abrufen
export const getUserById = (req: Request, res: Response) => {
  const user = users.find(u => u.id === parseInt(req.params.id));

  if (!user) {
    return res.status(404).json({ error: "User nicht gefunden" });
  }

  res.json({ data: user });
};

// POST /api/users – Neuen User erstellen
export const createUser = (req: Request, res: Response) => {
  const { name, email, rolle }: NeuerUser = req.body;

  // Duplikat pruefen
  if (users.find(u => u.email === email)) {
    return res.status(409).json({ error: "E-Mail existiert bereits" });
  }

  const neuerUser: User = {
    id: nextId++,
    name,
    email,
    rolle: rolle || 'user',
    erstelltAm: new Date()
  };

  users.push(neuerUser);
  res.status(201).json({ data: neuerUser });
};

// PUT /api/users/:id – User aktualisieren
export const updateUser = (req: Request, res: Response) => {
  const index = users.findIndex(u => u.id === parseInt(req.params.id));

  if (index === -1) {
    return res.status(404).json({ error: "User nicht gefunden" });
  }

  const update: UserUpdate = req.body;
  users[index] = { ...users[index], ...update };

  res.json({ data: users[index] });
};

// DELETE /api/users/:id – User loeschen
export const deleteUser = (req: Request, res: Response) => {
  const index = users.findIndex(u => u.id === parseInt(req.params.id));

  if (index === -1) {
    return res.status(404).json({ error: "User nicht gefunden" });
  }

  const geloeschterUser = users.splice(index, 1)[0];
  res.json({ data: geloeschterUser, message: "User geloescht" });
};

Insbesondere die Struktur des Prompts ist dabei entscheidend für gute Ergebnisse.

Routes definieren

Darüber hinaus bietet dieser Abschnitt konkrete Beispiele und Tipps.

// src/routes/users.ts
import { Router } from 'express';
import {
  getUsers, getUserById, createUser,
  updateUser, deleteUser
} from '../controllers/users';

const router = Router();

router.get('/', getUsers);
router.get('/:id', getUserById);
router.post('/', createUser);
router.put('/:id', updateUser);
router.delete('/:id', deleteUser);

export default router;
// In src/index.ts hinzufuegen:
import userRoutes from './routes/users';
app.use('/api/users', userRoutes);

Weiterhin ist es ratsam, die Ergebnisse immer kritisch zu prüfen.


5. Middleware

Vor allem für den praktischen Einsatz sind diese Informationen wertvoll.

// src/middleware/logger.ts
import { Request, Response, NextFunction } from 'express';

export const logger = (req: Request, res: Response, next: NextFunction) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const dauer = Date.now() - start;
    console.log(`${req.method} ${req.path} ${res.statusCode} ${dauer}ms`);
  });
  
  next();
};

// In index.ts:
app.use(logger);

Darüber hinaus lässt sich das Beispiel leicht erweitern.


6. Eingabe-Validierung

Im Folgenden findest du alle wichtigen Details dazu.

# Zod installieren
npm install zod

Somit sparst du Zeit und erhältst qualitativ hochwertigeren Output.

// src/middleware/validate.ts
import { z } from 'zod';
import { Request, Response, NextFunction } from 'express';

export const userSchema = z.object({
  name: z.string().min(2, "Name muss mindestens 2 Zeichen haben"),
  email: z.string().email("Ungueltige E-Mail"),
  rolle: z.enum(["admin", "user"]).optional()
});

export const validate = (schema: z.ZodSchema) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const result = schema.safeParse(req.body);
    
    if (!result.success) {
      return res.status(400).json({
        error: "Validierungsfehler",
        details: result.error.errors
      });
    }
    
    next();
  };
};

// In routes/users.ts:
router.post('/', validate(userSchema), createUser);

7. Datenbank anbinden (MongoDB)

Dabei spielen mehrere Faktoren eine wichtige Rolle.

# MongoDB Driver installieren
npm install mongoose
npm install -D @types/mongoose

Natürlich solltest du den generierten Code vor dem Einsatz testen.

// src/models/User.ts
import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
  name: { type: String, required: true, minlength: 2 },
  email: { type: String, required: true, unique: true },
  passwort: { type: String, required: true },
  rolle: { type: String, enum: ['admin', 'user'], default: 'user' }
}, { timestamps: true });

export const UserModel = mongoose.model('User', userSchema);

// Datenbankverbindung in index.ts:
import mongoose from 'mongoose';

mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/tutorial')
  .then(() => console.log('✅ MongoDB verbunden'))
  .catch(err => console.error('❌ MongoDB Fehler:', err));

Vor allem die detaillierten Anweisungen sorgen für präzisere Ergebnisse.


8. Authentifizierung mit JWT

Tatsächlich ist dieser Bereich besonders wichtig für Entwickler.

npm install jsonwebtoken bcryptjs
npm install -D @types/jsonwebtoken @types/bcryptjs

Dabei zeigt dieses Beispiel den grundlegenden Ansatz.

// src/middleware/auth.ts
import jwt from 'jsonwebtoken';
import { Request, Response, NextFunction } from 'express';

const JWT_SECRET = process.env.JWT_SECRET || 'geheim';

// Token generieren
export const generiereToken = (userId: string): string => {
  return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '7d' });
};

// Auth Middleware
export const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: "Kein Token angegeben" });
  }

  try {
    const decoded = jwt.verify(token, JWT_SECRET) as { userId: string };
    (req as any).userId = decoded.userId;
    next();
  } catch {
    res.status(401).json({ error: "Ungueltiger Token" });
  }
};

// Geschuetzte Route:
router.get('/profil', authMiddleware, getProfil);

9. Error Handling

Insbesondere für den Einstieg sind die folgenden Informationen hilfreich.

// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';

class ApiError extends Error {
  statusCode: number;
  constructor(statusCode: number, message: string) {
    super(message);
    this.statusCode = statusCode;
  }
}

export const errorHandler = (
  err: Error,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  if (err instanceof ApiError) {
    return res.status(err.statusCode).json({ error: err.message });
  }

  console.error('Unerwarteter Fehler:', err);
  res.status(500).json({ error: 'Interner Serverfehler' });
};

// Nutzung in Controller:
throw new ApiError(404, "User nicht gefunden");

Deshalb empfiehlt es sich, den Prompt schrittweise zu verfeinern.


10. API testen und deployen

Testen mit curl

Im Grunde vereinfacht dieser Ansatz den gesamten Workflow erheblich.

# GET alle User
curl http://localhost:3000/api/users

# POST neuer User
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Peter","email":"peter@test.de"}'

# PUT User aktualisieren
curl -X PUT http://localhost:3000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"Metin Celik"}'

# DELETE User loeschen
curl -X DELETE http://localhost:3000/api/users/2

Außerdem kannst du den Prompt für verschiedene Programmiersprachen anpassen.

Deployment als Docker Container

Ebenso wichtig ist es, die Best Practices zu kennen.

# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]

Tatsächlich lässt sich dieser Code direkt in dein Projekt übernehmen.


Naechste Schritte

Zusammenfassend lässt sich sagen, dass dies ein zentraler Aspekt ist.

  • API-Design vertiefen: AI fuer REST API Design
  • GraphQL lernen: Darüber hinaus a href=“/kuenstliche-intelligenz/ai-fuer-graphql/“>AI fuer GraphQL-Entwicklung
  • Testing: Ebenfalls a href=“/kuenstliche-intelligenz/ai-tools-fuer-automatisierte-tests/“>AI Tools fuer automatisierte Tests
  • Docker Deployment: Docker Tutorial fuer Containerisierung
  • Udemy-Kurse: Vertiefe dein Wissen mit einem JavaScript/Node.js Kurs

Profi-Tipp: Nutze ChatGPT Plus oder GitHub Copilot um API-Endpoints zu generieren. Beschreibe dein Datenmodell und lass die AI den Boilerplate-Code erzeugen – dann passe ihn an deine Beduerfnisse an.