feat(docs): add architecture principles for using API routes over Server Actions in Next.js

This commit is contained in:
Nils-Johan Gynther
2026-04-19 18:32:54 +02:00
parent 051fb11714
commit 068e8a58e5
+47 -1
View File
@@ -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/products*` | explicit regel | `recipe-api:8080` ⚠️ |
| `/api/inventory*` | 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) - **Framework:** Next.js 16.2 (App Router, server + client components)
- **Språk:** TypeScript 5.4.5 - **Språk:** TypeScript 5.4.5