initial commit
This commit is contained in:
298
templates/api-route.template.ts
Normal file
298
templates/api-route.template.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* 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
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
Reference in New Issue
Block a user