ai-wpa/templates/api-route.template.ts

299 lines
7.4 KiB
TypeScript

/**
* API Route Template
*
* Usage: Copy this file to create new API routes
* 1. Replace TEMPLATE_NAME with your route name
* 2. Implement your route handlers (GET, POST, PUT, DELETE)
* 3. Add proper validation and error handling
*/
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { authMiddleware } from '@/lib/auth-middleware'
// Request validation schemas
const GetRequestSchema = z.object({
// Define query parameters
page: z.string().optional().default('1').transform(Number),
limit: z.string().optional().default('10').transform(Number),
search: z.string().optional(),
})
const PostRequestSchema = z.object({
// Define request body structure
name: z.string().min(1, 'Name is required'),
description: z.string().optional(),
tags: z.array(z.string()).optional(),
})
const PutRequestSchema = z.object({
// Define update request body
id: z.string().min(1, 'ID is required'),
name: z.string().min(1, 'Name is required').optional(),
description: z.string().optional(),
})
// Type definitions
type GetParams = z.infer<typeof GetRequestSchema>
type PostBody = z.infer<typeof PostRequestSchema>
type PutBody = z.infer<typeof PutRequestSchema>
/**
* GET /api/template-route
* Retrieve items with pagination and filtering
*/
export async function GET(request: NextRequest) {
try {
// Authentication check (remove if public endpoint)
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Parse and validate query parameters
const { searchParams } = new URL(request.url)
const rawParams = Object.fromEntries(searchParams.entries())
const params = GetRequestSchema.parse(rawParams)
// Implement your business logic here
const { page, limit, search } = params
// Example: Database query
// const items = await db.collection.find({
// ...(search && { name: { $regex: search, $options: 'i' } }),
// })
// .skip((page - 1) * limit)
// .limit(limit)
// .toArray();
// Mock response
const items = [
{ id: '1', name: 'Example Item 1', description: 'Description 1' },
{ id: '2', name: 'Example Item 2', description: 'Description 2' },
]
return NextResponse.json({
success: true,
data: {
items,
pagination: {
page,
limit,
total: items.length,
totalPages: Math.ceil(items.length / limit),
},
},
})
} catch (error) {
console.error('GET /api/template-route error:', error)
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Invalid query parameters', details: error.issues },
{ status: 400 }
)
}
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
/**
* POST /api/template-route
* Create a new item
*/
export async function POST(request: NextRequest) {
try {
// Authentication check
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Parse and validate request body
const rawBody = await request.json()
const body = PostRequestSchema.parse(rawBody)
// Implement your business logic here
const { name, description, tags } = body
// Example: Database insertion
// const newItem = await db.collection.insertOne({
// name,
// description,
// tags,
// createdBy: user.id,
// createdAt: new Date(),
// });
// Mock response
const newItem = {
id: 'new-item-id',
name,
description,
tags,
createdBy: user.id,
createdAt: new Date().toISOString(),
}
return NextResponse.json(
{
success: true,
data: newItem,
},
{ status: 201 }
)
} catch (error) {
console.error('POST /api/template-route error:', error)
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Invalid request body', details: error.issues },
{ status: 400 }
)
}
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
/**
* PUT /api/template-route
* Update an existing item
*/
export async function PUT(request: NextRequest) {
try {
// Authentication check
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Parse and validate request body
const rawBody = await request.json()
const body = PutRequestSchema.parse(rawBody)
// Implement your business logic here
const { id, name, description } = body
// Example: Database update
// const updatedItem = await db.collection.findOneAndUpdate(
// { _id: id, createdBy: user.id }, // Ensure user owns the item
// {
// $set: {
// ...(name && { name }),
// ...(description && { description }),
// updatedAt: new Date(),
// }
// },
// { returnDocument: 'after' }
// );
// if (!updatedItem.value) {
// return NextResponse.json(
// { error: 'Item not found or unauthorized' },
// { status: 404 }
// );
// }
// Mock response
const updatedItem = {
id,
name: name || 'Existing Name',
description: description || 'Existing Description',
updatedAt: new Date().toISOString(),
}
return NextResponse.json({
success: true,
data: updatedItem,
})
} catch (error) {
console.error('PUT /api/template-route error:', error)
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Invalid request body', details: error.issues },
{ status: 400 }
)
}
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
/**
* DELETE /api/template-route/[id]
* Delete an item
*/
export async function DELETE(request: NextRequest, { params }: { params: { id: string } }) {
try {
// Authentication check
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { id } = params
if (!id) {
return NextResponse.json({ error: 'ID is required' }, { status: 400 })
}
// Implement your business logic here
// Example: Database deletion
// const deletedItem = await db.collection.findOneAndDelete({
// _id: id,
// createdBy: user.id, // Ensure user owns the item
// });
// if (!deletedItem.value) {
// return NextResponse.json(
// { error: 'Item not found or unauthorized' },
// { status: 404 }
// );
// }
return NextResponse.json({
success: true,
message: 'Item deleted successfully',
})
} catch (error) {
console.error('DELETE /api/template-route error:', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}
/**
* Common Response Types:
*
* Success Response:
* {
* success: true,
* data: any,
* message?: string
* }
*
* Error Response:
* {
* error: string,
* details?: any,
* code?: string
* }
*
* Pagination Response:
* {
* success: true,
* data: {
* items: any[],
* pagination: {
* page: number,
* limit: number,
* total: number,
* totalPages: number
* }
* }
* }
*/