api-route-generator
Generate Next.js Route Handlers (API routes) with proper patterns and validation.
$ npx -y skills add Fujigo-Software/f5-framework-claude --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Generate Next.js Route Handlers (API routes) with proper patterns and validation.
Agent definition
api-route-generator.mdNext.js API Route Generator Agent
Role
Generate Next.js Route Handlers (API routes) with proper patterns and validation.
Triggers
- "create api"
- "api route"
- "route handler"
- "nextjs api"
Capabilities
- Generate route.ts files with HTTP methods
- Implement request/response handling
- Add Zod validation
- Handle authentication
- Generate typed responses
- Create OpenAPI documentation
Input Requirements
required:
- route: string # API route path
- methods: array # HTTP methods (GET, POST, etc.)
optional:
- entity: string # Entity name for CRUD
- auth_required: boolean # Requires authentication
- validation: object # Zod schema definition
- response_type: string # Response format
Output Structure
app/api/{route}/
├── route.ts # Route handler
└── types.ts # Request/Response types (if complex)Generation Rules
1. Basic Route Handler
// app/api/products/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';
import { db } from '@/lib/db';
// GET /api/products
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const page = Number(searchParams.get('page')) || 1;
const limit = Number(searchParams.get('limit')) || 10;
const skip = (page - 1) * limit;
const [products, total] = await Promise.all([
db.product.findMany({
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
db.product.count(),
]);
return NextResponse.json({
data: products,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
});
} catch (error) {
console.error('GET /api/products error:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
// POST /api/products
const createProductSchema = z.object({
name: z.string().min(2).max(100),
description: z.string().max(1000).optional(),
price: z.number().min(0),
categoryId: z.string().uuid(),
});
export async function POST(request: Request) {
try {
const body = await request.json();
const validatedData = createProductSchema.safeParse(body);
if (!validatedData.success) {
return NextResponse.json(
{ error: 'Validation failed', details: validatedData.error.flatten() },
{ status: 400 }
);
}
const product = await db.product.create({
data: validatedData.data,
});
return NextResponse.json(product, { status: 201 });
} catch (error) {
console.error('POST /api/products error:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}2. Dynamic Route Handler
// app/api/products/[id]/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';
import { db } from '@/lib/db';
interface RouteParams {
params: { id: string };
}
// GET /api/products/[id]
export async function GET(request: Request, { params }: RouteParams) {
try {
const product = await db.product.findUnique({
where: { id: params.id },
include: { category: true },
});
if (!product) {
return NextResponse.json(
{ error: 'Product not found' },
{ status: 404 }
);
}
return NextResponse.json(product);
} catch (error) {
console.error(`GET /api/products/${params.id} error:`, error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
// PATCH /api/products/[id]
const updateProductSchema = z.object({
name: z.string().min(2).max(100).optional(),
description: z.string().max(1000).optional(),
price: z.number().min(0).optional(),
categoryId: z.string().uuid().optional(),
});
export async function PATCH(request: Request, { params }: RouteParams) {
try {
const body = await request.json();
const validatedData = updateProductSchema.safeParse(body);
if (!validatedData.success) {
return NextResponse.json(
{ error: 'Validation failed', details: validatedData.error.flatten() },
{ status: 400 }
);
}
const product = await db.product.update({
where: { id: params.id },
data: validatedData.data,
});
return NextResponse.json(product);
} catch (error) {
if ((error as any).code === 'P2025') {
return NextResponse.json(
{ error: 'Product not found' },
{ status: 404 }
);
}
console.error(`PATCH /api/products/${params.id} error:`, error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
// DELETE /api/products/[id]
export async function DELETE(request: Request, { params }: RouteParams) {
try {
await db.product.delete({
where: { id: params.id },
});
return new NextResponse(null, { status: 204 });
} catch (error) {
if ((error as any).code === 'P2025') {
return NextResponse.json(
{ error: 'Product not found' },
{ status: 404 }
);
}
console.error(`DELETE /api/products/${params.id} error:`, error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}3. Authenticated Route
// app/api/user/profile/route.ts
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
export async function GET() {
const session = await auth();
if (!session?.user) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
const user = await db.user.findUnique({
where: { id: session.user.id },
select: {
id: true,
name: true,
email: true,
image: true,
createdAt: true,
},
});
return NextResponse.json(user);
}
export async function PATCH(requeRead more
Next.js API Route Generator Agent
Role
Generate Next.js Route Handlers (API routes) with proper patterns and validation.
Triggers
- "create api"
- "api route"
- "route handler"
- "nextjs api"
Capabilities
- Generate route.ts files with HTTP methods
- Implement request/response handling
- Add Zod validation
- Handle authentication
- Generate typed responses
- Create OpenAPI documentation
Input Requirements
required: - route: string # API route path - methods: array # HTTP methods (GET, POST, etc.) optional: - entity: string # Entity name for CRUD - auth_required: boolean # Requires authentication - validation: object # Zod schema definition - response_type: string # Response format
Output Structure
app/api/{route}/
├── route.ts # Route handler
└── types.ts # Request/Response types (if complex)Generation Rules
1. Basic Route Handler
// app/api/products/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';
import { db } from '@/lib/db';
// GET /api/products
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const page = Number(searchParams.get('page')) || 1;
const limit = Number(searchParams.get('limit')) || 10;
const skip = (page - 1) * limit;
const [products, total] = await Promise.all([
db.product.findMany({
skip,
take: limit,
orderBy: { createdAt: 'desc' },
}),
db.product.count(),
]);
return NextResponse.json({
data: products,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
});
} catch (error) {
console.error('GET /api/products error:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
// POST /api/products
const createProductSchema = z.object({
name: z.string().min(2).max(100),
description: z.string().max(1000).optional(),
price: z.number().min(0),
categoryId: z.string().uuid(),
});
export async function POST(request: Request) {
try {
const body = await request.json();
const validatedData = createProductSchema.safeParse(body);
if (!validatedData.success) {
return NextResponse.json(
{ error: 'Validation failed', details: validatedData.error.flatten() },
{ status: 400 }
);
}
const product = await db.product.create({
data: validatedData.data,
});
return NextResponse.json(product, { status: 201 });
} catch (error) {
console.error('POST /api/products error:', error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}2. Dynamic Route Handler
// app/api/products/[id]/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';
import { db } from '@/lib/db';
interface RouteParams {
params: { id: string };
}
// GET /api/products/[id]
export async function GET(request: Request, { params }: RouteParams) {
try {
const product = await db.product.findUnique({
where: { id: params.id },
include: { category: true },
});
if (!product) {
return NextResponse.json(
{ error: 'Product not found' },
{ status: 404 }
);
}
return NextResponse.json(product);
} catch (error) {
console.error(`GET /api/products/${params.id} error:`, error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
// PATCH /api/products/[id]
const updateProductSchema = z.object({
name: z.string().min(2).max(100).optional(),
description: z.string().max(1000).optional(),
price: z.number().min(0).optional(),
categoryId: z.string().uuid().optional(),
});
export async function PATCH(request: Request, { params }: RouteParams) {
try {
const body = await request.json();
const validatedData = updateProductSchema.safeParse(body);
if (!validatedData.success) {
return NextResponse.json(
{ error: 'Validation failed', details: validatedData.error.flatten() },
{ status: 400 }
);
}
const product = await db.product.update({
where: { id: params.id },
data: validatedData.data,
});
return NextResponse.json(product);
} catch (error) {
if ((error as any).code === 'P2025') {
return NextResponse.json(
{ error: 'Product not found' },
{ status: 404 }
);
}
console.error(`PATCH /api/products/${params.id} error:`, error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}
// DELETE /api/products/[id]
export async function DELETE(request: Request, { params }: RouteParams) {
try {
await db.product.delete({
where: { id: params.id },
});
return new NextResponse(null, { status: 204 });
} catch (error) {
if ((error as any).code === 'P2025') {
return NextResponse.json(
{ error: 'Product not found' },
{ status: 404 }
);
}
console.error(`DELETE /api/products/${params.id} error:`, error);
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}3. Authenticated Route
// app/api/user/profile/route.ts
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
export async function GET() {
const session = await auth();
if (!session?.user) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
const user = await db.user.findUnique({
where: { id: session.user.id },
select: {
id: true,
name: true,
email: true,
image: true,
createdAt: true,
},
});
return NextResponse.json(user);
}
export async function PATCH(requeAI-Powered Development Framework for Claude Code
Repo: Fujigo-Software/f5-framework-claude
Other agents on f5-framework.
- database-expert
Expert database architect specializing in schema design, query optimization, data modeling, and migration strategies. Japanese: データベースエキスパート
Open agent - devops-architect
Expert DevOps architect specializing in CI/CD pipelines, infrastructure as code, containerization, and monitoring. Japanese: DevOpsアーキテクト
Open agent - 11-mobile-architect
Mobile app architecture specialist. iOS, Android, React Native, Flutter.
Open agent - 12-backend-architect
Backend architecture specialist. Microservices, APIs, databases.
Open agent - 13-frontend-architect
Frontend architecture specialist. React, Vue, Angular, Next.js.
Open agent - 14-data-architect
Data architecture specialist. Databases, ETL, analytics.
Open agent

