# FormData Empty at Backend - Debugging Guide

## Problem
- Frontend shows data in payload
- Backend receives empty FormData
- `await request.formData()` returns empty object

## Root Causes

### 1. **Request Body Already Consumed** (Most Common)
If any middleware or code reads the request body BEFORE `await request.formData()`, the stream is consumed and can't be read again.

**Solution:**
- Add this at the VERY START of your route.ts POST handler (BEFORE any permission checks):

```typescript
export async function POST(request: NextRequest) {
  // ✅ IMPORTANT: Get formData FIRST, before any middleware or permission checks
  const formData = await request.formData();
  
  // Now do permission checks with the cloned request if needed
  return withCreatePermission(request, "tbl_student_registrations", async () => {
    // Now use formData that was already parsed
    const userId = 1;
    
    // Rest of your code...
  });
}
```

### 2. **Content-Type Header Issue**
If Content-Type is not `multipart/form-data; boundary=...`, the server won't parse FormData.

**Debug:**
Add this to your backend route to log the actual headers:

```typescript
export async function POST(request: NextRequest) {
  console.log("📋 Request Headers:");
  console.log("Content-Type:", request.headers.get("content-type"));
  console.log("All Headers:", {
    "content-type": request.headers.get("content-type"),
    "content-length": request.headers.get("content-length"),
  });
  
  const formData = await request.formData();
  
  console.log("✅ FormData Entries:");
  for (const [key, value] of formData.entries()) {
    if (value instanceof File) {
      console.log(`  ${key}: File(${value.name}, ${value.size} bytes)`);
    } else {
      console.log(`  ${key}: ${value}`);
    }
  }
  
  // Rest of your code...
}
```

### 3. **Frontend: FormData Not Properly Created**

**Debug Frontend:**
Add this in CreateUpdateForm.tsx before calling onSubmit:

```typescript
const handleFormSubmit = async () => {
    const submitData = new FormData();
    const fileKeys = new Set(Object.keys(fileUploads));

    // Append non-file form data
    Object.entries(data).forEach(([key, value]) => {
        if (fileKeys.has(key)) return;
        if (value !== null && value !== undefined && value !== '') {
            if (Array.isArray(value)) {
                value.forEach((item, index) => {
                    submitData.append(`${key}[${index}]`, String(item));
                });
            } else {
                submitData.append(key, String(value));
            }
        }
    });

    // Append file uploads
    Object.entries(fileUploads).forEach(([key, files]) => {
        if (!files) return;
        if (Array.isArray(files)) {
            files.forEach(file => {
                submitData.append(`${key}[]`, file);
            });
        } else {
            submitData.append(key, files as File);
        }
    });

    // Append remove flags
    removedFiles.forEach(field => {
        submitData.append(`remove_${field}`, 'true');
    });

    // 🔍 DEBUG: Log FormData before sending
    console.log("📤 FormData being sent:");
    for (const [key, value] of submitData.entries()) {
        if (value instanceof File) {
            console.log(`  ${key}: File(${value.name}, ${value.size})`);
        } else {
            console.log(`  ${key}: ${value}`);
        }
    }

    await onSubmit(submitData);
};
```

### 4. **Axios Configuration Issue**

Ensure your axiosConfig.ts has NO Content-Type header for FormData:

```typescript
// src/config/axiosConfig.ts - CORRECT VERSION
axiosInstance.interceptors.request.use((config) => {
    if (!(config.data instanceof FormData)) {
        config.headers["Content-Type"] = "application/json";
    }
    // ✅ For FormData: DO NOT set Content-Type
    // Let axios/browser set it with correct boundary
    
    // If you have other headers, only add them for non-FormData
    if (!(config.data instanceof FormData)) {
        // Add any other headers here
    }
    
    return config;
});
```

## Step-by-Step Fix

### Step 1: Add Backend Logging
Add the debug logging code to [src/app/api/backend/students/route.ts](src/app/api/backend/students/route.ts) POST method.

### Step 2: Add Frontend Logging
Add the console.log code to [src/app/(crm)/components/CreateUpdateFrom/CreateUpdateFrom.tsx](src/app/(crm)/components/CreateUpdateFrom/CreateUpdateFrom.tsx) handleFormSubmit.

### Step 3: Test and Check Browser Console
1. Open browser DevTools (F12)
2. Go to Console tab
3. Try creating/updating a student
4. Check console logs on both frontend and backend
5. Also check Network tab → find the POST request → inspect the request payload

### Step 4: Share Results
Post the console logs, and I'll help you fix the specific issue.

## Quick Fixes to Try First

```typescript
// 1️⃣ In StudentsClient.tsx handleCreateStudent, ensure FormData is passed:
const handleCreateStudent = useCallback(async (formData: FormData) => {
    console.log("Received FormData:", formData instanceof FormData);
    
    const response = await apiService({
        url: "/backend/students",
        method: "POST",
        data: formData,  // ✅ Make sure this is actually FormData instance
    });
    // ...
}, []);

// 2️⃣ Ensure apiService handles FormData correctly:
// In src/services/apiService.ts
if (data instanceof FormData) {
    console.log("✅ Sending as FormData");
} else {
    console.log("❌ WARNING: Data is not FormData instance:", typeof data);
}
```

## Common Issues Summary

| Issue | Symptom | Fix |
|-------|---------|-----|
| Body already read | FormData empty | Parse formData FIRST before permission checks |
| Wrong Content-Type | FormData empty | Remove manual Content-Type header for FormData |
| FormData not created | No data in payload | Check CreateUpdateForm handleFormSubmit |
| axios Headers override | Wrong Content-Type sent | Check axiosConfig interceptor |
