API Route Snippets
Common API route patterns in ShipKit
API Route Snippets
Basic Route Handler
// src/app/api/posts/route.ts
import { NextResponse } from "next/server";
import { ValidationService } from "@/server/services/validation-service";
import { ErrorService } from "@/server/services/error-service";
import { z } from "zod";
const createPostSchema = z.object({
title: z.string().min(1),
content: z.string().optional(),
});
export async function POST(req: Request) {
try {
const json = await req.json();
const result = await ValidationService.validate(createPostSchema, json);
if (!result.success) {
return NextResponse.json(
{ error: result.error },
{ status: 400 }
);
}
const post = await db.post.create({
data: result.data,
});
return NextResponse.json(post, { status: 201 });
} catch (error) {
const appError = ErrorService.handleError(error);
return NextResponse.json(
{ error: appError },
{ status: appError.code === "UNAUTHORIZED" ? 401 : 500 }
);
}
}
Protected Route Handler
// src/app/api/protected/posts/route.ts
import { auth } from "@/server/auth";
import { NextResponse } from "next/server";
import { ValidationService } from "@/server/services/validation-service";
import { ErrorService } from "@/server/services/error-service";
import { z } from "zod";
const schema = z.object({
title: z.string().min(1),
content: z.string().optional(),
});
export async function POST(req: Request) {
try {
const session = await auth();
if (!session?.user) {
return ErrorService.throwUnauthorized("Not authenticated");
}
const json = await req.json();
const result = await ValidationService.validate(schema, json);
if (!result.success) {
return NextResponse.json(
{ error: result.error },
{ status: 400 }
);
}
const post = await db.post.create({
data: {
...result.data,
authorId: session.user.id,
},
});
return NextResponse.json(post, { status: 201 });
} catch (error) {
const appError = ErrorService.handleError(error);
return NextResponse.json(
{ error: appError },
{ status: appError.code === "UNAUTHORIZED" ? 401 : 500 }
);
}
}
File Upload Handler
// src/app/api/upload/route.ts
import { auth } from "@/server/auth";
import { NextResponse } from "next/server";
import { ErrorService } from "@/server/services/error-service";
export async function POST(req: Request) {
try {
const session = await auth();
if (!session?.user) {
return ErrorService.throwUnauthorized("Not authenticated");
}
const formData = await req.formData();
const file = formData.get("file") as File;
if (!file) {
return ErrorService.throwBadRequest("No file provided");
}
// Process file upload
// Example: Upload to S3, process image, etc.
const uploadedFile = await uploadToStorage(file);
return NextResponse.json(uploadedFile, { status: 201 });
} catch (error) {
const appError = ErrorService.handleError(error);
return NextResponse.json(
{ error: appError },
{ status: appError.code === "UNAUTHORIZED" ? 401 : 500 }
);
}
}
async function uploadToStorage(file: File) {
// Implement file upload logic
return {
url: "https://example.com/files/image.jpg",
filename: file.name,
size: file.size,
type: file.type,
};
}
Dynamic Route Handler
// src/app/api/posts/[id]/route.ts
import { auth } from "@/server/auth";
import { NextResponse } from "next/server";
import { ErrorService } from "@/server/services/error-service";
interface RouteContext {
params: { id: string };
}
export async function GET(req: Request, { params }: RouteContext) {
try {
const session = await auth();
if (!session?.user) {
return ErrorService.throwUnauthorized("Not authenticated");
}
const post = await db.post.findUnique({
where: { id: params.id },
});
if (!post) {
return ErrorService.throwNotFound("Post not found");
}
return NextResponse.json(post);
} catch (error) {
const appError = ErrorService.handleError(error);
return NextResponse.json(
{ error: appError },
{ status: appError.code === "NOT_FOUND" ? 404 : 500 }
);
}
}
export async function DELETE(req: Request, { params }: RouteContext) {
try {
const session = await auth();
if (!session?.user) {
return ErrorService.throwUnauthorized("Not authenticated");
}
const post = await db.post.findUnique({
where: { id: params.id },
});
if (!post) {
return ErrorService.throwNotFound("Post not found");
}
if (post.authorId !== session.user.id) {
return ErrorService.throwForbidden("Not authorized");
}
await db.post.delete({
where: { id: params.id },
});
return NextResponse.json({ success: true });
} catch (error) {
const appError = ErrorService.handleError(error);
return NextResponse.json(
{ error: appError },
{ status: appError.code === "NOT_FOUND" ? 404 : 500 }
);
}
}