feat(docs): add architecture principles for using API routes over Server Actions in Next.js
This commit is contained in:
+47
-1
@@ -121,9 +121,55 @@ Next.js API routes som kräver server-side auth och ska gå via frontend måste
|
||||
| `/api/products*` | explicit regel | `recipe-api:8080` ⚠️ |
|
||||
| `/api/inventory*` | explicit regel | `recipe-api:8080` ⚠️ |
|
||||
|
||||
---
|
||||
|
||||
## Arkitekturprincip: API routes framför Server Actions
|
||||
|
||||
> **Regel: Använd Next.js API routes (`/app/api/...`) för all mutation från klientkomponenter. Använd INTE Server Actions för detta.**
|
||||
|
||||
### Bakgrund
|
||||
|
||||
Next.js Server Actions returnerar alltid ett **RSC-payload** (React Server Component flight-format) som svar — även om funktionen bara returnerar ett vanligt JSON-objekt. När en klientkomponent anropar en Server Action via `startTransition` försöker React tolka svaret som ett siduppdateringspaket. Detta orsakar kraschen **"can't reload page"** / `TypeError: r is not iterable` i React 19 om sidans RSC-träd inte kan återskapas korrekt (t.ex. p.g.a. Caddy-routing, auth-state eller timing).
|
||||
|
||||
### Rätt mönster: Next.js API route
|
||||
|
||||
```
|
||||
Klientkomponent → fetch('/api/admin/...') → Next.js API route → Backend API
|
||||
```
|
||||
|
||||
- API routen körs server-side och har tillgång till sessionen via `auth()` → kan lägga till auth-headers
|
||||
- Returnerar ren JSON — inga RSC-payload-problem
|
||||
- Caddy-safe: använd `/api/admin/` som prefix (faller igenom till `recipe-frontend:3000`)
|
||||
- Klientkomponenten hanterar UI-state lokalt efter svar (uppdatera/ta bort ur lokal state)
|
||||
|
||||
**Exempel** (se [app/api/admin/product/[id]/route.ts](frontend/app/api/admin/product/%5Bid%5D/route.ts)):
|
||||
```ts
|
||||
// API route (server-side, har session)
|
||||
export async function PATCH(req, { params }) {
|
||||
const authHeaders = await getAuthHeaders(); // använder auth()
|
||||
const res = await fetch(`${API_BASE}/api/products/${id}`, { method: 'PATCH', headers: authHeaders, ... });
|
||||
return Response.json(await res.json());
|
||||
}
|
||||
|
||||
// Klientkomponent
|
||||
const res = await fetch(`/api/admin/product/${id}`, { method: 'PATCH', body: JSON.stringify(data) });
|
||||
const updated = await res.json();
|
||||
setProducts(prev => prev.map(p => p.id === updated.id ? updated : p)); // lokal state-uppdatering
|
||||
```
|
||||
|
||||
### När är Server Actions OK?
|
||||
|
||||
Server Actions kan fortfarande användas för operationer som **inte anropas från klientkomponenter med `startTransition`**, t.ex.:
|
||||
- Form submissions i rena Server Components (inget `useTransition`)
|
||||
- Admin-operationer som ändå triggar en helsidsladdning efteråt
|
||||
|
||||
### Befintliga undantag att känna till
|
||||
|
||||
Dessa Server Actions finns kvar men bör migreras om de orsakar problem:
|
||||
- `bulkSetCategory` — anropas från `AdminProductList` (klientkomponent)
|
||||
- `suggestProductCategory` / `suggestBulkCategories` — AI-kategorisering, anropas från klient
|
||||
|
||||
|
||||
## Frontend
|
||||
|
||||
- **Framework:** Next.js 16.2 (App Router, server + client components)
|
||||
- **Språk:** TypeScript 5.4.5
|
||||
|
||||
Reference in New Issue
Block a user