1// ── API Route: app/api/posts/route.ts ────────────────────────────
2import { NextRequest, NextResponse } from "next/server";
3
4export async function GET(request: NextRequest) {
5 const { searchParams } = new URL(request.url);
6 const page = Number(searchParams.get("page") ?? 1);
7 const limit = Number(searchParams.get("limit") ?? 10);
8
9 const posts = await db.post.findMany({
10 skip: (page - 1) * limit,
11 take: limit,
12 orderBy: { createdAt: "desc" },
13 });
14
15 return NextResponse.json({ posts, page }, { status: 200 });
16}
17
18export async function POST(request: NextRequest) {
19 const body = await request.json();
20
21 // Validate with zod
22 const result = PostSchema.safeParse(body);
23 if (!result.success) {
24 return NextResponse.json({ error: result.error.flatten() }, { status: 400 });
25 }
26
27 const post = await db.post.create({ data: result.data });
28 return NextResponse.json(post, { status: 201 });
29}
30
31// ── API Route: app/api/posts/[id]/route.ts ────────────────────────
32export async function GET(
33 request: NextRequest,
34 { params }: { params: Promise<{ id: string }> }
35) {
36 const { id } = await params;
37 const post = await db.post.findUnique({ where: { id } });
38
39 if (!post) return NextResponse.json({ error: "Not found" }, { status: 404 });
40 return NextResponse.json(post);
41}
42
43export async function DELETE(
44 request: NextRequest,
45 { params }: { params: Promise<{ id: string }> }
46) {
47 const { id } = await params;
48 await db.post.delete({ where: { id } });
49 return new NextResponse(null, { status: 204 });
50}
51
52// ── Middleware: middleware.ts (project root) ───────────────────────
53import { NextResponse } from "next/server";
54import type { NextRequest } from "next/server";
55
56export function middleware(request: NextRequest) {
57 const token = request.cookies.get("auth-token");
58 const pathname = request.nextUrl.pathname;
59
60 // Protect /dashboard routes
61 if (pathname.startsWith("/dashboard") && !token) {
62 return NextResponse.redirect(new URL("/login", request.url));
63 }
64
65 // Add custom header to all responses
66 const response = NextResponse.next();
67 response.headers.set("X-Frame-Options", "DENY");
68 return response;
69}
70
71// Only run middleware on these paths
72export const config = {
73 matcher: ["/dashboard/:path*", "/api/:path*"],
74};
75
76// ── Webhook handler (Stripe example) ─────────────────────────────
77export async function POST(request: NextRequest) {
78 const body = await request.text();
79 const signature = request.headers.get("stripe-signature")!;
80
81 let event;
82 try {
83 event = stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
84 } catch {
85 return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
86 }
87
88 if (event.type === "checkout.session.completed") {
89 await handleCheckout(event.data.object);
90 }
91
92 return NextResponse.json({ received: true });
93}
94
95import { z } from "zod";
96const PostSchema = z.object({ title: z.string().min(3), content: z.string() });
97const db = { post: { findMany: async (q: any) => [], create: async (d: any) => ({}), findUnique: async (q: any) => null, delete: async (q: any) => {} } };
98const stripe = { webhooks: { constructEvent: (b: any, s: any, secret: any) => ({ type: "", data: { object: {} } }) } };
99async function handleCheckout(session: any) {}