Loading...
Loading...
> Create API endpoints with Next.js App Router and learn Fabrk's patterns.
Fabrk uses Next.js 15 App Router for API routes. All routes are in src/app/api/.
Create a new file at src/app/api/hello/route.ts
1import { NextResponse } from "next/server";23export async function GET() {4 return NextResponse.json({ message: "Hello World" });5}67export async function POST(request: Request) {8 const body = await request.json();9 return NextResponse.json({ received: body });10}
Add authentication to your route
1import { auth } from "@/lib/auth";2import { NextResponse } from "next/server";34export async function GET() {5 const session = await auth();67 if (!session?.user) {8 return NextResponse.json(9 { error: "Unauthorized" },10 { status: 401 }11 );12 }1314 // Access user data15 const userId = session.user.id;16 const email = session.user.email;1718 return NextResponse.json({19 userId,20 email,21 message: "You are authenticated!"22 });23}
Always validate input with Zod schemas
1import { NextResponse } from "next/server";2import { z } from "zod";34const createUserSchema = z.object({5 name: z.string().min(2).max(50),6 email: z.string().email(),7 age: z.number().min(18).optional(),8});910export async function POST(request: Request) {11 try {12 const body = await request.json();13 const validated = createUserSchema.parse(body);1415 // Use validated data16 return NextResponse.json({ user: validated });1718 } catch (_) {19 if (error instanceof z.ZodError) {20 return NextResponse.json(21 { error: "Validation failed", details: error.errors },22 { status: 400 }23 );24 }25 return NextResponse.json(26 { error: "Internal server error" },27 { status: 500 }28 );29 }30}
Use Prisma to interact with your database
1import { prisma } from "@/lib/prisma";2import { auth } from "@/lib/auth";3import { NextResponse } from "next/server";45export async function GET() {6 const session = await auth();7 if (!session?.user) {8 return NextResponse.json({ error: "Unauthorized" }, { status: 401 });9 }1011 const user = await prisma.user.findUnique({12 where: { id: session.user.id },13 select: {14 id: true,15 name: true,16 email: true,17 createdAt: true,18 },19 });2021 return NextResponse.json({ user });22}
Use this consistent error handling pattern
1import { logger } from "@/lib/logger";2import { NextResponse } from "next/server";34export async function POST(request: Request) {5 try {6 // Your logic here7 const result = await someOperation();8 return NextResponse.json({ data: result });910 } catch (_) {11 logger.error("Operation failed:", {12 error: error instanceof Error ? error.message : "Unknown error",13 });1415 return NextResponse.json(16 { error: "Operation failed" },17 { status: 500 }18 );19 }20}
200 - Success201 - Created400 - Bad request (invalid input)401 - Unauthorized (not logged in)403 - Forbidden (no permission)404 - Not found422 - Validation error500 - Server error[ERROR]: CORS error in browser console
Solution: Add CORS headers in middleware or API route
// In route.ts
const headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
};
return NextResponse.json({ data }, { headers });[ERROR]: 405 Method Not Allowed
Solution: Verify export name matches HTTP method
// Must be named GET, POST, PUT, DELETE (uppercase)
export async function GET() { } // Correct
export async function get() { } // Wrong - won't work[ERROR]: Request timeout
Solution: Optimize database queries and add timeouts
// Add index to frequent query fields in schema.prisma
model User {
email String @unique // Indexed automatically
name String @db.Index // Add index for searches
}[ERROR]: Cannot read properties of undefined
Solution: Always validate request data with Zod
// Always validate before accessing
const body = await request.json();
const validated = schema.parse(body); // Throws if invalid
const value = validated.field; // Safe to access