Master Next.js Route Handlers patterns for Google Antigravity IDE API development
# Next.js Route Handlers Patterns for Google Antigravity IDE
Build APIs with Route Handlers using Google Antigravity IDE. This guide covers HTTP methods, streaming, authentication, and webhook patterns.
## Basic Route Handler
```typescript
// app/api/users/route.ts
import { NextResponse } from "next/server";
import { db } from "@/lib/db";
import { auth } from "@/lib/auth";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get("page") || "1");
const limit = parseInt(searchParams.get("limit") || "20");
const search = searchParams.get("q");
const where = search ? { OR: [{ name: { contains: search } }, { email: { contains: search } }] } : {};
const [users, total] = await Promise.all([
db.user.findMany({
where,
skip: (page - 1) * limit,
take: limit,
select: { id: true, name: true, email: true, role: true, createdAt: true },
}),
db.user.count({ where }),
]);
return NextResponse.json({
users,
pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
});
}
export async function POST(request: Request) {
const session = await auth();
if (!session?.user || session.user.role !== "admin") {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
const body = await request.json();
const user = await db.user.create({
data: {
email: body.email,
name: body.name,
role: body.role || "user",
},
});
return NextResponse.json({ user }, { status: 201 });
} catch (error) {
return NextResponse.json({ error: "Failed to create user" }, { status: 500 });
}
}
```
## Dynamic Route Handler
```typescript
// app/api/users/[id]/route.ts
import { NextResponse } from "next/server";
import { db } from "@/lib/db";
import { auth } from "@/lib/auth";
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
const user = await db.user.findUnique({
where: { id: params.id },
select: { id: true, name: true, email: true, role: true, createdAt: true },
});
if (!user) {
return NextResponse.json({ error: "User not found" }, { status: 404 });
}
return NextResponse.json({ user });
}
export async function PATCH(
request: Request,
{ params }: { params: { id: string } }
) {
const session = await auth();
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Users can only update their own profile unless admin
if (session.user.id !== params.id && session.user.role !== "admin") {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await request.json();
const user = await db.user.update({
where: { id: params.id },
data: body,
});
return NextResponse.json({ user });
}
export async function DELETE(
request: Request,
{ params }: { params: { id: string } }
) {
const session = await auth();
if (!session?.user || session.user.role !== "admin") {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
await db.user.delete({ where: { id: params.id } });
return new NextResponse(null, { status: 204 });
}
```
## Streaming Response
```typescript
// app/api/stream/route.ts
export async function GET() {
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
const message = JSON.stringify({ count: i, timestamp: Date.now() }) + "\n";
controller.enqueue(encoder.encode(message));
await new Promise((resolve) => setTimeout(resolve, 1000));
}
controller.close();
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
}
```
## Webhook Handler
```typescript
// app/api/webhooks/stripe/route.ts
import { headers } from "next/headers";
import Stripe from "stripe";
import { db } from "@/lib/db";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(request: Request) {
const body = await request.text();
const signature = headers().get("stripe-signature")!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!);
} catch (error) {
return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
}
switch (event.type) {
case "checkout.session.completed":
const session = event.data.object as Stripe.Checkout.Session;
await db.order.update({
where: { id: session.metadata?.orderId },
data: { status: "paid", paidAt: new Date() },
});
break;
case "customer.subscription.updated":
const subscription = event.data.object as Stripe.Subscription;
await db.subscription.update({
where: { stripeSubscriptionId: subscription.id },
data: { status: subscription.status },
});
break;
}
return NextResponse.json({ received: true });
}
```
## Best Practices for Google Antigravity IDE
When using Route Handlers with Google Antigravity, validate input with Zod. Use proper HTTP status codes. Implement authentication checks. Handle errors consistently. Let Gemini 3 generate route handlers from your API specifications.
Google Antigravity excels at building REST APIs with Route Handlers.This Next.js prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their next.js implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Next.js projects, consider mentioning your framework version, coding style, and any specific libraries you're using.