Skip to content
← Back to blog
NestJSTypeScriptTutorialDeutschREST API

NestJS Tutorial auf Deutsch: REST API mit TypeScript erstellen

Firas Sayah·May 12, 2026·8 min read

Ich habe in den letzten drei Jahren ueber 20 Backend-APIs gebaut -- mit Express, Fastify, Koa und sogar PHP. Aber als ich NestJS zum ersten Mal ausprobiert habe, wusste ich sofort: Das ist anders. Innerhalb von zwei Stunden hatte ich eine sauber strukturierte API mit Validierung, Fehlerbehandlung und Dependency Injection. Kein chaotisches Routing, keine "wo lege ich das jetzt hin"-Momente. Einfach Klarheit.

In diesem Tutorial zeige ich dir genau, wie du das auch schaffst.

Entwickler arbeitet an einer modernen REST API

Warum NestJS?

NestJS ist das beliebteste Backend-Framework fuer Node.js. Es bringt Struktur in serverseitiges JavaScript, die man sonst nur von Frameworks wie Spring Boot oder ASP.NET kennt: Module, Dependency Injection, Decorators und eine klare Schichtenarchitektur.

Wenn du aus der Angular-Welt kommst, fuehlt sich NestJS sofort vertraut an. Die Architektur ist nahezu identisch: Module buendeln Features, Services enthalten die Geschaeftslogik, und Controller verarbeiten HTTP-Anfragen. Selbst die CLI-Befehle sind aehnlich. Wenn du diese Synergie zwischen Angular und NestJS genauer verstehen moechtest, lies unseren Artikel Warum Angular + NestJS die beste Kombination fuer SaaS ist.

Dieses Tutorial fuehrt dich Schritt fuer Schritt durch die Erstellung einer vollstaendigen REST API.

Voraussetzungen

Du brauchst Node.js 18 oder hoeher. Pruefe deine Version:

node --version

Installiere die NestJS CLI global:

npm install -g @nestjs/cli

Grundkenntnisse in TypeScript sind hilfreich, aber kein Muss. Wir erklaeren alles, was du wissen musst.

Cloudrix SaaS Starter ships with this pre-configured and tested.

Skip weeks of boilerplate — auth, payments, multi-tenancy, and deployment included out of the box.

Try the live demo →

Schritt 1: Projekt erstellen

Erstelle ein neues NestJS-Projekt mit der CLI:

nest new meine-api
cd meine-api

Waehle npm oder yarn als Paketmanager. Die CLI erzeugt eine vollstaendige Projektstruktur:

src/
  app.controller.ts    # Verarbeitet HTTP-Anfragen
  app.service.ts       # Geschaeftslogik
  app.module.ts        # Hauptmodul
  main.ts              # Startpunkt der Anwendung

Starte den Entwicklungsserver:

npm run start:dev

Oeffne http://localhost:3000 im Browser. Du solltest "Hello World!" sehen.

Schritt 2: Das erste Feature-Modul

Jedes Feature bekommt ein eigenes Modul. Wir erstellen eine API fuer Artikel-Verwaltung:

nest generate module artikel
nest generate controller artikel --no-spec
nest generate service artikel --no-spec

NestJS erzeugt drei Dateien in src/artikel/ und registriert das Modul automatisch in app.module.ts. So bleibt dein Code organisiert, auch wenn die Anwendung waechst.

Saubere Code-Architektur mit Modulen

Schritt 3: Datenmodell definieren

Erstelle src/artikel/artikel.entity.ts:

export interface Artikel {
  id: string;
  titel: string;
  inhalt: string;
  autor: string;
  veroeffentlicht: boolean;
  erstelltAm: Date;
}

In einer produktiven Anwendung wuerdest du hier eine TypeORM-Entity mit Datenbank-Dekoratoren verwenden. Mehr dazu findest du in unserem TypeORM Multi-Tenancy Guide. Fuer dieses Tutorial arbeiten wir zunaechst mit einem In-Memory-Array.

Schritt 4: Service mit Geschaeftslogik

Der Service enthaelt die gesamte Geschaeftslogik. Oeffne src/artikel/artikel.service.ts:

import { Injectable, NotFoundException } from '@nestjs/common';
import { Artikel } from './artikel.entity';
import { v4 as uuid } from 'uuid';

@Injectable()
export class ArtikelService {
  private artikel: Artikel[] = [];

  alleArtikelAbrufen(): Artikel[] {
    return this.artikel;
  }

  artikelNachId(id: string): Artikel {
    const artikel = this.artikel.find((a) => a.id === id);
    if (!artikel) {
      throw new NotFoundException(`Artikel mit ID "${id}" nicht gefunden`);
    }
    return artikel;
  }

  artikelErstellen(titel: string, inhalt: string, autor: string): Artikel {
    const neuerArtikel: Artikel = {
      id: uuid(),
      titel,
      inhalt,
      autor,
      veroeffentlicht: false,
      erstelltAm: new Date(),
    };
    this.artikel.push(neuerArtikel);
    return neuerArtikel;
  }

  artikelAktualisieren(id: string, titel: string, inhalt: string): Artikel {
    const artikel = this.artikelNachId(id);
    artikel.titel = titel;
    artikel.inhalt = inhalt;
    return artikel;
  }

  artikelLoeschen(id: string): void {
    const artikel = this.artikelNachId(id);
    this.artikel = this.artikel.filter((a) => a.id !== artikel.id);
  }

  artikelVeroeffentlichen(id: string): Artikel {
    const artikel = this.artikelNachId(id);
    artikel.veroeffentlicht = true;
    return artikel;
  }
}

Beachte den @Injectable()-Dekorator. Er teilt NestJS mit, dass diese Klasse per Dependency Injection in andere Klassen injiziert werden kann. NotFoundException erzeugt automatisch eine 404-HTTP-Antwort.

Pro-Tipp: Halte deine Services schlank. Wenn ein Service mehr als 200 Zeilen hat, ist es Zeit, ihn aufzuteilen. Ich erstelle oft einen separaten "Validation-Service" fuer komplexe Geschaeftsregeln.

Schritt 5: Eingabevalidierung mit DTOs

DTOs (Data Transfer Objects) definieren, welche Daten der Client senden darf. Installiere die Validierungsbibliotheken:

npm install class-validator class-transformer

Erstelle src/artikel/dto/erstelle-artikel.dto.ts:

import { IsString, IsNotEmpty, MinLength, MaxLength } from 'class-validator';

export class ErstelleArtikelDto {
  @IsString()
  @IsNotEmpty({ message: 'Titel darf nicht leer sein' })
  @MinLength(3, { message: 'Titel muss mindestens 3 Zeichen lang sein' })
  @MaxLength(200)
  titel: string;

  @IsString()
  @IsNotEmpty({ message: 'Inhalt darf nicht leer sein' })
  inhalt: string;

  @IsString()
  @IsNotEmpty()
  autor: string;
}

Aktiviere die globale Validierung in src/main.ts:

import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
    }),
  );
  await app.listen(3000);
}
bootstrap();

whitelist: true entfernt unbekannte Felder automatisch. forbidNonWhitelisted: true gibt einen Fehler zurueck, wenn unbekannte Felder gesendet werden.

🚀 Willst du diese Grundlagen ueberspringen und direkt mit einer produktionsreifen API starten? Der Cloudrix SaaS Starter enthaelt eine fertige NestJS-API mit Authentifizierung, Validierung, Stripe-Zahlungen und Multi-Tenancy -- alles schon konfiguriert. Schau dir die Live-Demo an.

Schritt 6: Controller erstellen

Der Controller verbindet HTTP-Endpunkte mit Service-Methoden. Oeffne src/artikel/artikel.controller.ts:

import {
  Controller, Get, Post, Put, Delete,
  Param, Body, Patch, HttpCode, HttpStatus,
} from '@nestjs/common';
import { ArtikelService } from './artikel.service';
import { ErstelleArtikelDto } from './dto/erstelle-artikel.dto';

@Controller('artikel')
export class ArtikelController {
  constructor(private readonly artikelService: ArtikelService) {}

  @Get()
  alleAbrufen() {
    return this.artikelService.alleArtikelAbrufen();
  }

  @Get(':id')
  nachIdAbrufen(@Param('id') id: string) {
    return this.artikelService.artikelNachId(id);
  }

  @Post()
  erstellen(@Body() dto: ErstelleArtikelDto) {
    return this.artikelService.artikelErstellen(
      dto.titel,
      dto.inhalt,
      dto.autor,
    );
  }

  @Put(':id')
  aktualisieren(
    @Param('id') id: string,
    @Body() dto: ErstelleArtikelDto,
  ) {
    return this.artikelService.artikelAktualisieren(id, dto.titel, dto.inhalt);
  }

  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  loeschen(@Param('id') id: string) {
    this.artikelService.artikelLoeschen(id);
  }

  @Patch(':id/veroeffentlichen')
  veroeffentlichen(@Param('id') id: string) {
    return this.artikelService.artikelVeroeffentlichen(id);
  }
}

Jeder Dekorator (@Get(), @Post(), etc.) mapped eine HTTP-Methode auf eine Controller-Methode. @Param() extrahiert URL-Parameter, @Body() den Request-Body.

Schritt 7: API testen

Teste deine API mit curl:

# Artikel erstellen
curl -X POST http://localhost:3000/artikel \
  -H "Content-Type: application/json" \
  -d '{"titel": "Mein erster Artikel", "inhalt": "NestJS ist grossartig!", "autor": "Max"}'

# Alle Artikel abrufen
curl http://localhost:3000/artikel

# Einzelnen Artikel abrufen
curl http://localhost:3000/artikel/DEINE_ARTIKEL_ID

# Artikel veroeffentlichen
curl -X PATCH http://localhost:3000/artikel/DEINE_ARTIKEL_ID/veroeffentlichen

# Artikel loeschen
curl -X DELETE http://localhost:3000/artikel/DEINE_ARTIKEL_ID

Teste auch die Validierung:

curl -X POST http://localhost:3000/artikel \
  -H "Content-Type: application/json" \
  -d '{"titel": "ab"}'

Du erhaeltst eine 400-Antwort mit deutschen Fehlermeldungen, die genau beschreiben, welche Validierungen fehlgeschlagen sind. Wenn du lernen moechtest, wie man solche APIs automatisiert testet, wirf einen Blick auf unseren NestJS Testing Guide mit Jest.

Schritt 8: Datenbankanbindung mit TypeORM

Fuer eine produktive Anwendung brauchst du eine echte Datenbank. Installiere TypeORM und den PostgreSQL-Treiber:

npm install @nestjs/typeorm typeorm pg

Konfiguriere die Datenbankverbindung in app.module.ts:

import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      database: 'meine_api',
      username: 'postgres',
      password: 'postgres',
      autoLoadEntities: true,
      synchronize: true, // Nur in der Entwicklung verwenden!
    }),
    ArtikelModule,
  ],
})
export class AppModule {}

Wandle dein Interface in eine TypeORM-Entity um:

import {
  Entity, PrimaryGeneratedColumn, Column, CreateDateColumn,
} from 'typeorm';

@Entity()
export class Artikel {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  titel: string;

  @Column('text')
  inhalt: string;

  @Column()
  autor: string;

  @Column({ default: false })
  veroeffentlicht: boolean;

  @CreateDateColumn()
  erstelltAm: Date;
}

Registriere die Entity im Modul und injiziere das Repository in den Service. TypeORM uebernimmt die SQL-Generierung vollstaendig. Fuer fortgeschrittene Datenbank-Patterns wie Multi-Tenancy empfehle ich unseren Artikel ueber Multi-Tenant Architektur mit NestJS.

PostgreSQL Datenbank in Aktion

Schritt 9: Fehlerbehandlung

NestJS bietet einen globalen Exception-Filter. Erstelle einen eigenen fuer strukturierte Fehlermeldungen:

import {
  ExceptionFilter, Catch, ArgumentsHost, HttpException,
} from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      nachricht: exception.message,
      zeitstempel: new Date().toISOString(),
    });
  }
}

Registriere den Filter global in main.ts:

app.useGlobalFilters(new HttpExceptionFilter());

Naechste Schritte

Du hast jetzt eine funktionierende REST API mit NestJS. Um sie produktionsreif zu machen, solltest du folgende Themen anschauen:

Fertige Loesung: Monate an Arbeit sparen 💡

Wenn du alle diese Komponenten bereits fertig konfiguriert und getestet haben moechtest, schau dir den Cloudrix SaaS Starter an. Er enthaelt ein vollstaendiges NestJS-Backend mit Authentifizierung, Rollenverwaltung, Stripe-Zahlungen, Multi-Tenancy und Terraform-Deployment auf AWS. Statt Wochen mit Infrastruktur zu verbringen, kannst du dich sofort auf dein Produkt konzentrieren.

Ich nutze diesen Stack selbst fuer meine eigenen Projekte, und er hat mir buchstaeblich Monate an Entwicklungszeit gespart.

Bereit loszulegen? Probier die Live-Demo aus oder sieh dir die Preise an -- die Lite-Version ist komplett kostenlos.

F

Firas Sayah

Senior Software Engineer

Full-stack developer with 5+ years building production SaaS applications with NestJS and Angular.