Files
lumina-nextjs-template/.claude/commands/api.md
2025-12-23 04:19:57 +01:00

287 lines
6.8 KiB
Markdown

# API Route Generator
Du bist ein Experte für Next.js API Routes. Erstelle sichere, typisierte API Endpoints.
## Deine Aufgaben
Erstelle API Routes die:
- Next.js App Router Patterns folgen
- TypeScript mit korrekten Types verwenden
- Error Handling implementieren
- Input Validation durchführen
- Supabase Integration nutzen
## API Route Template
```typescript
// app/api/[resource]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
// GET - Liste oder einzelnes Item
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (id) {
// Single item
const { data, error } = await supabase
.from('table')
.select('*')
.eq('id', id)
.single();
if (error) throw error;
return NextResponse.json(data);
}
// List
const { data, error } = await supabase
.from('table')
.select('*')
.order('created_at', { ascending: false });
if (error) throw error;
return NextResponse.json(data);
} catch (error) {
console.error('GET error:', error);
return NextResponse.json(
{ error: 'Failed to fetch data' },
{ status: 500 }
);
}
}
// POST - Neues Item erstellen
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// Validation
if (!body.name) {
return NextResponse.json(
{ error: 'Name is required' },
{ status: 400 }
);
}
const { data, error } = await supabase
.from('table')
.insert(body)
.select()
.single();
if (error) throw error;
return NextResponse.json(data, { status: 201 });
} catch (error) {
console.error('POST error:', error);
return NextResponse.json(
{ error: 'Failed to create item' },
{ status: 500 }
);
}
}
// PUT - Item aktualisieren
export async function PUT(request: NextRequest) {
try {
const body = await request.json();
const { id, ...updates } = body;
if (!id) {
return NextResponse.json(
{ error: 'ID is required' },
{ status: 400 }
);
}
const { data, error } = await supabase
.from('table')
.update(updates)
.eq('id', id)
.select()
.single();
if (error) throw error;
return NextResponse.json(data);
} catch (error) {
console.error('PUT error:', error);
return NextResponse.json(
{ error: 'Failed to update item' },
{ status: 500 }
);
}
}
// DELETE - Item löschen
export async function DELETE(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json(
{ error: 'ID is required' },
{ status: 400 }
);
}
const { error } = await supabase
.from('table')
.delete()
.eq('id', id);
if (error) throw error;
return NextResponse.json({ success: true });
} catch (error) {
console.error('DELETE error:', error);
return NextResponse.json(
{ error: 'Failed to delete item' },
{ status: 500 }
);
}
}
```
## Dynamic Route
```typescript
// app/api/users/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
interface RouteParams {
params: Promise<{ id: string }>;
}
export async function GET(request: NextRequest, { params }: RouteParams) {
const { id } = await params;
const { data, error } = await supabase
.from('users')
.select('*')
.eq('id', id)
.single();
if (error || !data) {
return NextResponse.json({ error: 'User not found' }, { status: 404 });
}
return NextResponse.json(data);
}
```
## Auth Protected Route
```typescript
// app/api/protected/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export async function GET(request: NextRequest) {
const cookieStore = await cookies();
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value;
},
},
}
);
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// User is authenticated
return NextResponse.json({ user });
}
```
## Input Validation mit Zod
```typescript
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
role: z.enum(['user', 'admin']).optional().default('user'),
});
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// Validate input
const result = createUserSchema.safeParse(body);
if (!result.success) {
return NextResponse.json(
{ error: 'Validation failed', details: result.error.flatten() },
{ status: 400 }
);
}
const validatedData = result.data;
// ... create user
} catch (error) {
return NextResponse.json({ error: 'Server error' }, { status: 500 });
}
}
```
## Response Helpers
```typescript
// lib/api-response.ts
import { NextResponse } from 'next/server';
export function successResponse<T>(data: T, status = 200) {
return NextResponse.json({ success: true, data }, { status });
}
export function errorResponse(message: string, status = 500) {
return NextResponse.json({ success: false, error: message }, { status });
}
export function notFoundResponse(resource = 'Resource') {
return errorResponse(`${resource} not found`, 404);
}
export function unauthorizedResponse() {
return errorResponse('Unauthorized', 401);
}
export function validationErrorResponse(errors: unknown) {
return NextResponse.json(
{ success: false, error: 'Validation failed', details: errors },
{ status: 400 }
);
}
```
## Best Practices
1. **Error Handling** - Immer try/catch verwenden
2. **Input Validation** - Alle Inputs validieren (Zod empfohlen)
3. **Auth Check** - Geschützte Routen absichern
4. **Status Codes** - Korrekte HTTP Status Codes
5. **Logging** - Errors loggen für Debugging
---
Frage den Benutzer: Welche API Route möchtest du erstellen?
Beschreibe die gewünschte Ressource und Operationen.