// app/api/images/route.ts
import { NextResponse } from
'next/server';
import { connectDB } from '@/lib/db';
export async function GET() {
const db = await connectDB();
const images = await db
.collection('images')
.find({ public: true })
.limit(50)
.toArray();
return NextResponse.json(images);
}
export async function POST(
request: Request
) {
const body = await request.json();
// Validate, save, return
const db = await connectDB();
const result = await db
.collection('images')
.insertOne(body);
return NextResponse.json(
{ id: result.insertedId },
{ status: 201 }
);
}
// middleware.ts
import { NextResponse } from
'next/server';
import type { NextRequest } from
'next/server';
export function middleware(
request: NextRequest
) {
// Protect /editor routes
if (request.nextUrl.pathname
.startsWith('/editor')) {
const token =
request.cookies.get('token');
if (!token) {
return NextResponse.redirect(
new URL('/login', request.url));
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/editor/:path*'],
};
// app/actions/favorites.ts
'use server';
import { getAuthUser } from '@/lib/auth';
import { connectDB } from '@/lib/db';
import { revalidatePath } from
'next/cache';
export async function toggleFavorite(
imageId: string
) {
const user = await getAuthUser();
const db = await connectDB();
await db.collection('favorites')
.updateOne(
{ userId: user._id, imageId },
{ $set: { favorited: true } },
{ upsert: true }
);
revalidatePath('/gallery');
}
// In a component — no fetch needed:
// <button onClick={
// () => toggleFavorite(image.id)
// }>
// ♥ Favorite
// </button>
// Architecture comparison:
Standalone Express:
✅ Complex APIs, WebSockets
✅ Background jobs (BullMQ)
✅ Independent scaling
✅ Team separation
❌ Separate deployment
Next.js API routes:
✅ Simple CRUD
✅ Colocated with frontend
✅ Single deployment
✅ Server Actions (no API needed)
❌ No WebSockets, no long-running
Hybrid (PixelCraft's choice):
Next.js → public pages, gallery,
landing, simple API
Express → core API, WebSockets,
background workers, heavy logic
// The answer is almost always hybrid.
git switch -c feature/PIXELCRAFT-088-nextjs-api
git add pixelcraft-web/
git commit -m "Add Next.js API routes + middleware + Server Actions (PIXELCRAFT-088)"
git push origin feature/PIXELCRAFT-088-nextjs-api
# PR → Review → Merge → Close ticket ✅
Monolith vs microservices vs "modular monolith."
The industry trend in 2025 is toward colocated full-stack apps for most projects, with separate services only when scale or team structure demands it.