299 lines
7.4 KiB
TypeScript
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
|
|
* }
|
|
* }
|
|
* }
|
|
*/
|