- Add fresh app structure (auth, tenant, mail, insight, docs, panel) - Include CMS content, API routes, scripts, and config - Migrate UI components, themes, and extensions to fresh runtime
7.5 KiB
7.5 KiB
API Migration Guide - Next.js to Fresh + Deno
This document tracks the migration of Next.js API routes to Fresh handlers with Deno runtime.
Migration Status
✅ Completed
Core Infrastructure
middleware.ts- Fresh middleware for authentication and session managementlib/authGateway.deno.ts- Cookie management with Web APIsserver/serviceConfig.deno.ts- Service URL configuration
API Routes Migrated
/api/ping→routes/api/ping.ts/api/auth/login→routes/api/auth/login.ts/api/auth/session→routes/api/auth/session.ts/api/render-markdown→routes/api/render-markdown.ts/api/content-meta→routes/api/content-meta.ts
🚧 In Progress
- Authentication routes (register, verify-email, MFA)
- Protected API routes (users, admin, mail, etc.)
- Dynamic routes ([...segments])
📋 Pending
The following Next.js API routes need to be migrated:
Auth Routes
app/api/auth/register/route.tsapp/api/auth/register/verify/route.tsapp/api/auth/register/send/route.tsapp/api/auth/verify-email/route.tsapp/api/auth/verify-email/send/route.tsapp/api/auth/mfa/setup/route.tsapp/api/auth/mfa/verify/route.tsapp/api/auth/mfa/status/route.tsapp/api/auth/mfa/disable/route.ts
Protected API Routes
app/api/users/route.tsapp/api/admin/settings/route.tsapp/api/admin/users/metrics/route.tsapp/api/admin/users/[userId]/role/route.ts
Mail API Routes
app/api/mail/inbox/route.tsapp/api/mail/send/route.tsapp/api/mail/namespace/route.tsapp/api/mail/message/[id]/route.tsapp/api/mail/ai/summarize/route.tsapp/api/mail/ai/reply-suggest/route.tsapp/api/mail/ai/classify/route.ts
AI & Task Routes
app/api/askai/route.tsapp/api/rag/query/route.tsapp/api/task/[...segments]/route.tsapp/api/agent/[...segments]/route.ts
Migration Patterns
1. Basic API Handler
Next.js Pattern:
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
return NextResponse.json({ data: 'value' })
}
Fresh Pattern:
import { Handlers } from '$fresh/server.ts'
export const handler: Handlers = {
GET(_req, _ctx) {
return new Response(JSON.stringify({ data: 'value' }), {
headers: { 'Content-Type': 'application/json' },
})
},
}
2. Cookie Management
Next.js Pattern:
import { cookies } from 'next/headers'
const token = cookies().get('session')?.value
const res = NextResponse.json({ ... })
res.cookies.set('session', token, { httpOnly: true })
Fresh Pattern:
import { getSessionToken, applySessionCookie } from '@/lib/authGateway.deno.ts'
const token = getSessionToken(req)
const headers = new Headers({ 'Content-Type': 'application/json' })
applySessionCookie(headers, token)
return new Response(JSON.stringify({ ... }), { headers })
3. Query Parameters
Next.js Pattern:
const path = request.nextUrl.searchParams.get('path')
Fresh Pattern:
const url = new URL(req.url)
const path = url.searchParams.get('path')
4. Request Body
Next.js Pattern:
const body = await request.json()
Fresh Pattern:
const body = await req.json()
5. Dynamic Routes
Next.js Pattern:
// app/api/mail/message/[id]/route.ts
export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
const { id } = params
}
Fresh Pattern:
// routes/api/mail/message/[id].ts
import { Handlers } from '$fresh/server.ts'
export const handler: Handlers = {
GET(_req, ctx) {
const { id } = ctx.params
},
}
6. Catch-all Routes
Next.js Pattern:
// app/api/task/[...segments]/route.ts
export async function POST(request: NextRequest, { params }: { params: { segments: string[] } }) {
const { segments } = params
}
Fresh Pattern:
// routes/api/task/[...segments].ts
import { Handlers } from '$fresh/server.ts'
export const handler: Handlers = {
POST(_req, ctx) {
const segments = ctx.params.segments.split('/')
},
}
7. Middleware State Access
Fresh Pattern:
import { Handlers } from '$fresh/server.ts'
import { FreshState } from '@/middleware.ts'
export const handler: Handlers<unknown, FreshState> = {
GET(_req, ctx) {
const user = ctx.state.user
const isAuthenticated = ctx.state.isAuthenticated
// ...
},
}
8. Environment Variables
Next.js Pattern:
const apiUrl = process.env.API_BASE_URL
Fresh Pattern:
const apiUrl = Deno.env.get('API_BASE_URL')
Key Differences
Response Construction
Next.js: Uses NextResponse helper
NextResponse.json(data, { status: 200 })
Fresh: Uses standard Response API
new Response(JSON.stringify(data), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
Cookie Handling
Next.js: Built-in cookie API with cookies() from next/headers
Fresh: Manual cookie parsing and Set-Cookie header management
- Use
getCookies(req)to parse request cookies - Use helper functions to set cookies in response headers
- See
lib/authGateway.deno.tsfor implementation
File System Access
Next.js: Uses Node.js fs module
import { readFile } from 'fs/promises'
const content = await readFile(path, 'utf-8')
Fresh/Deno: Uses Deno APIs
const content = await Deno.readTextFile(path)
const stats = await Deno.stat(path)
Subprocess Execution
Next.js: Uses Node.js child_process
import { execFile } from 'child_process'
execFile('git', ['log'], callback)
Fresh/Deno: Uses Deno.Command
const command = new Deno.Command('git', {
args: ['log'],
stdout: 'piped',
})
const { stdout } = await command.output()
Authentication Flow
Middleware (middleware.ts)
- Parses session and MFA cookies from request
- For protected routes: validates session token against Account Service
- Injects user context into
ctx.state - Returns 401 for unauthenticated API requests
- Redirects to login for unauthenticated page requests
Login Flow (routes/api/auth/login.ts)
- Validates credentials with Account Service
- On success: sets session cookie with token
- On MFA required: sets MFA challenge cookie
- Clears cookies on failure
Session Flow (routes/api/auth/session.ts)
- Gets session token from cookie
- Validates with Account Service
- Returns normalized user data
- DELETE method clears session (logout)
Testing Checklist
When migrating an API route, verify:
- Request parsing works (query params, body, headers)
- Response format matches original (status, headers, body)
- Error handling preserves status codes
- Cookie handling works correctly
- Authentication/authorization is enforced
- Deno permissions are sufficient (--allow-net, --allow-read, etc.)
- Environment variables are read correctly
- External service calls have timeouts
- Type safety is maintained
Next Steps
- Migrate authentication routes (register, verify-email, MFA)
- Migrate protected API routes with user context
- Migrate dynamic and catch-all routes
- Create integration tests for migrated routes
- Update frontend to use new API endpoints
- Remove Next.js route handlers from app/ directory