Express.js REST API mit Claude Code: TypeScript Backend 2026

Express.js bleibt der meistgenutzte Node.js-Framework — flexibel, erprobt, mit riesigem Ökosystem. Claude Code kennt alle Express-Patterns: TypeScript-Setup, Middleware-Stacks, Validierung, JWT-Auth, Error-Handling und OpenAPI-Dokumentation für produktionsreife Backends.

TypeScript-Setup und Projektstruktur

SetupExpress mit TypeScript einrichten

# Prompt: "Express.js REST API mit TypeScript, Prisma, Zod — Production-Setup" npm install express helmet cors morgan compression npm install -D typescript @types/express @types/node ts-node-dev // src/app.ts — Express App Factory import express, { Express } from 'express' import helmet from 'helmet' import cors from 'cors' import morgan from 'morgan' import compression from 'compression' export function createApp(): Express { const app = express() // Security-Middleware app.use(helmet()) app.use(cors({ origin: process.env.FRONTEND_URL, credentials: true })) app.use(compression()) app.use(morgan('combined')) app.use(express.json({ limit: '10mb' })) // Routes app.use('/api/v1/users', usersRouter) app.use('/api/v1/projects', projectsRouter) app.use('/health', (_, res) => res.json({ status: 'ok', ts: Date.now() })) // Error Handler (MUSS letzter Middleware sein) app.use(errorHandler) return app } // src/index.ts — Server Start const app = createApp() const PORT = env.PORT ?? 3001 app.listen(PORT, () => console.log(`Server läuft auf Port ${PORT}`))
Projektstruktur-Prompt: "Erstelle Express TypeScript Projektstruktur: src/routes, src/middleware, src/services, src/models, src/utils — mit Barrel-Exporten und klarer Schichtentrennung."

Router und Controller-Pattern

RouterRessourcen-basiertes Routing mit Zod

# Prompt: "Express Router für User-CRUD mit Zod-Validierung und Async-Wrapper" // src/middleware/validate.ts — Zod-Validierungs-Middleware export function validate(schema: AnyZodObject) { return (req: Request, res: Response, next: NextFunction) => { const result = schema.safeParse({ body: req.body, query: req.query, params: req.params }) if (!result.success) { return res.status(400).json({ errors: result.error.flatten() }) } req.validated = result.data next() } } // src/routes/users.ts const router = express.Router() const createUserSchema = z.object({ body: z.object({ name: z.string().min(2), email: z.string().email(), password: z.string().min(8) }) }) router.get('/', authenticate, asyncHandler(async (req, res) => { const { page = '1', limit = '20' } = req.query const users = await userService.findAll({ page: +page, limit: +limit }) res.json(users) })) router.post('/', validate(createUserSchema), asyncHandler(async (req, res) => { const user = await userService.create(req.validated.body) res.status(201).json(user) })) router.get('/:id', authenticate, asyncHandler(async (req, res) => { const user = await userService.findById(req.params.id) if (!user) throw new NotFoundError('User nicht gefunden') res.json(user) }))

JWT-Authentication Middleware

AuthJWT-Middleware mit Refresh-Token

# Prompt: "JWT-Auth-Middleware mit Access + Refresh Token, sichere Cookie-Strategie" // src/middleware/authenticate.ts import jwt from 'jsonwebtoken' export const authenticate: RequestHandler = (req, res, next) => { const token = req.headers.authorization?.replace('Bearer ', '') if (!token) return res.status(401).json({ error: 'Nicht authentifiziert' }) try { const payload = jwt.verify(token, env.JWT_SECRET) as JwtPayload req.user = { id: payload.sub, role: payload.role } next() } catch (err) { if (err instanceof jwt.TokenExpiredError) { return res.status(401).json({ error: 'Token abgelaufen', code: 'TOKEN_EXPIRED' }) } res.status(401).json({ error: 'Ungültiger Token' }) } } // Token generieren export function generateTokens(userId: string, role: string) { const accessToken = jwt.sign( { sub: userId, role }, env.JWT_SECRET, { expiresIn: '15m' } // Kurz — sicher ) const refreshToken = jwt.sign( { sub: userId }, env.JWT_REFRESH_SECRET, { expiresIn: '7d' } ) return { accessToken, refreshToken } } // RBAC: Role-Based Access Control export const authorize = (roles: string[]) => (req: Request, res: Response, next: NextFunction) => { if (!roles.includes(req.user.role)) return res.status(403).json({ error: 'Keine Berechtigung' }) next() }

Globales Error-Handling

ErrorsTypisierte Fehler und zentrales Error-Handling

# Prompt: "Erstelle typisierte Error-Klassen und zentralen Express Error-Handler" // src/errors/AppError.ts export class AppError extends Error { constructor( public message: string, public statusCode: number = 500, public code?: string ) { super(message) Object.setPrototypeOf(this, AppError.prototype) } } export class NotFoundError extends AppError { constructor(msg: string) { super(msg, 404, 'NOT_FOUND') } } export class UnauthorizedError extends AppError { constructor(msg: string) { super(msg, 401, 'UNAUTHORIZED') } } export class ConflictError extends AppError { constructor(msg: string) { super(msg, 409, 'CONFLICT') } } // src/middleware/errorHandler.ts export const errorHandler: ErrorRequestHandler = (err, req, res, next) => { console.error(`[${req.method}] ${req.path}`, err) if (err instanceof AppError) { return res.status(err.statusCode).json({ error: err.message, code: err.code }) } // Prisma-Fehler if (err.code === 'P2002') { // Unique Constraint return res.status(409).json({ error: 'Datensatz existiert bereits' }) } // Unbekannte Fehler: 500 res.status(500).json({ error: 'Interner Serverfehler' }) } // asyncHandler — Fehler weiterleiten ohne try/catch in jedem Route export const asyncHandler = (fn: RequestHandler): RequestHandler => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next)
Häufiger Fehler: Fehler in async Route-Handlers nicht zu next() weitergeben. Ohne asyncHandler-Wrapper bleibt Express bei unbehandelten Promise-Rejections hängen. Claude Code fügt den Wrapper automatisch ein.

OpenAPI-Dokumentation mit Swagger

# Prompt: "Swagger/OpenAPI-Docs für Express REST API mit swagger-jsdoc" npm install swagger-jsdoc swagger-ui-express // src/docs/swagger.ts const options = { definition: { openapi: '3.0.0', info: { title: 'API', version: '1.0.0' }, components: { securitySchemes: { bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' } } } }, apis: ['./src/routes/*.ts'] } app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerJsdoc(options))) // Route-Annotation /** * @openapi * /api/v1/users: * post: * summary: User erstellen * requestBody: * required: true * content: * application/json: * schema: * $ref: '#/components/schemas/CreateUser' * responses: * 201: * description: User erstellt */

Backend-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges Express-Modul mit TypeScript-Setup, Middleware-Stack, JWT-Auth, Error-Handling, Prisma-Integration und OpenAPI-Dokumentation — für produktionsreife REST-APIs.

14 Tage kostenlos testen →