Warum Node.js für Backend?
Node.js hat sich als feste Größe in der Backend-Entwicklung etabliert. Die Vorteile liegen auf der Hand:
- Eine Sprache überall: JavaScript/TypeScript im Frontend und Backend
- Große Ecosystem: NPM ist die größte Package Registry der Welt
- Performance: Non-blocking I/O macht Node.js ideal für I/O-intensive Anwendungen
- Entwicklerproduktivität: Schnelle Entwicklungszyklen, große Community
Aber Node.js allein ist nur eine Runtime. Für strukturierte Anwendungen brauchen Sie ein Framework.
Express vs. NestJS: Der Vergleich
Express: Minimalistisch und flexibel
Express ist das beliebteste Node.js-Framework – und das aus gutem Grund. Es ist einfach, schnell und gibt Ihnen maximale Freiheit:
const express = require('express');
const app = express();
app.get('/users', (req, res) => {
res.json([{ id: 1, name: 'Max' }]);
});
app.listen(3000);Vorteile von Express:
- Minimaler Overhead
- Schneller Einstieg
- Volle Kontrolle über die Architektur
- Riesige Community und Middleware-Ökosystem
Nachteile:
- Keine vorgegebene Struktur
- Architektur muss selbst definiert werden
- TypeScript-Integration erfordert Setup
- Bei wachsenden Projekten wird es schnell unübersichtlich
NestJS: Struktur und Skalierbarkeit
NestJS baut auf Express (oder Fastify) auf und bringt eine klare Architektur mit:
// users.controller.ts
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
findAll(): User[] {
return this.usersService.findAll();
}
@Post()
create(@Body() createUserDto: CreateUserDto): User {
return this.usersService.create(createUserDto);
}
}Vorteile von NestJS:
- Klare Architektur von Anfang an (Module, Controller, Services)
- TypeScript als First-Class-Citizen
- Dependency Injection out of the box
- Integrierte Validierung, Guards, Interceptors
- Gut dokumentiert mit aktiver Community
Nachteile:
- Steilere Lernkurve
- Mehr Boilerplate für kleine Projekte
- Opinionated – Sie arbeiten nach NestJS-Konventionen
NestJS-Architektur verstehen
NestJS folgt dem Prinzip der Modularität. Jedes Feature ist ein Modul:
src/
├── app.module.ts # Root-Modul
├── users/
│ ├── users.module.ts # Feature-Modul
│ ├── users.controller.ts
│ ├── users.service.ts
│ └── dto/
│ └── create-user.dto.ts
├── auth/
│ ├── auth.module.ts
│ ├── auth.controller.ts
│ ├── auth.service.ts
│ └── guards/
│ └── jwt-auth.guard.tsModule
Module gruppieren zusammengehörige Funktionalität:
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Für andere Module verfügbar
})
export class UsersModule {}Controller
Controller verarbeiten HTTP-Requests:
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string): Promise<User> {
return this.usersService.findOne(+id);
}
@Put(':id')
@UseGuards(JwtAuthGuard)
update(
@Param('id') id: string,
@Body() updateUserDto: UpdateUserDto,
): Promise<User> {
return this.usersService.update(+id, updateUserDto);
}
}Services
Services enthalten die Business-Logik:
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}
async findAll(): Promise<User[]> {
return this.usersRepository.find();
}
async create(createUserDto: CreateUserDto): Promise<User> {
const user = this.usersRepository.create(createUserDto);
return this.usersRepository.save(user);
}
}Praktische Features von NestJS
1. Validierung mit DTOs
// create-user.dto.ts
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsString()
name?: string;
}2. Guards für Authentifizierung
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
return super.canActivate(context);
}
}
// Verwendung
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}3. Interceptors für Logging/Transformation
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
const now = Date.now();
return next.handle().pipe(
tap(() => console.log(`Request took ${Date.now() - now}ms`)),
);
}
}Wann welches Framework?
Wählen Sie Express, wenn:
- Sie ein kleines Projekt oder Prototyp bauen
- Sie maximale Flexibilität brauchen
- Das Team Express bereits gut kennt
- Sie bewusst minimalen Overhead wollen
Wählen Sie NestJS, wenn:
- Sie eine skalierbare, wartbare API bauen
- Sie TypeScript nutzen wollen
- Sie mit einem Team arbeiten (Konsistenz durch Konventionen)
- Sie Features wie Validierung, Guards, Swagger-Docs out of the box wollen
Unsere Erfahrung
In unseren Projekten setzen wir für neue APIs fast immer auf NestJS. Der initiale Mehraufwand zahlt sich schnell aus: Die Codebase bleibt auch nach Monaten verständlich, neue Teammitglieder finden sich schnell zurecht, und Features wie Validierung oder Authentifizierung sind in Minuten implementiert.
Express nutzen wir noch für sehr kleine Services oder wenn wir in ein bestehendes Express-Projekt integrieren.