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/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
|
||||||
|
|||||||
Reference in New Issue
Block a user