-
-
Notifications
You must be signed in to change notification settings - Fork 22
API Tips & Middleware
This page serves as a practical guide for developers working on CodeNearby's backend routes. It explains best practices, usage tips, and how to properly use middleware to keep the API layer secure, efficient, and maintainable.
CodeNearby uses the App Router (Next.js 14) with app/api/.../route.ts convention. Each route file exports GET, POST, PATCH, or DELETE handlers.
Example:
app/
└── api/
└── friends/
├── request/
│ └── [id]/
│ └── route.ts
└── requests/
└── route.ts
- Use RESTful principles for endpoints.
- Group similar routes under the same folder.
- Use dynamic routes (e.g.,
[id]) for resource access.
Example route signature:
export async function POST(req: Request) {
// logic here
}Middleware runs before your actual API handler to perform:
- Auth validation
- Logging
- Input sanitization
- Rate limiting
Create a utility (e.g., lib/middleware.ts) and wrap handlers:
export function withMiddleware(handler: Function) {
return async (req: Request) => {
// common logic
return handler(req);
};
}Usage in route:
import { withMiddleware } from "@/lib/middleware";
export const GET = withMiddleware(async (req) => {
// actual logic
});Use it to protect sensitive endpoints. For example:
import { getServerSession } from "next-auth";
export async function withAuth(req: Request) {
const session = await getServerSession(authOptions);
if (!session?.user) {
return new Response("Unauthorized", { status: 401 });
}
return session;
}Protect public endpoints (e.g., AI search, public posts) using Redis or in-memory counters.
Example strategy:
- Limit to 10 requests/minute per IP
- Use a key like
rate-limit:<ip>in Redis - Return 429 status on overflow
Use a shared utility like:
import { isRateLimited } from "@/lib/rateLimiter";
if (await isRateLimited(ip)) {
return new Response("Rate limit exceeded", { status: 429 });
}Use consistent structure for API errors:
return new Response(JSON.stringify({
success: false,
error: "Invalid input"
}), { status: 400 });Avoid generic 500 errors unless necessary. Log details internally, but return safe error messages.
Use console.log or a logger wrapper during development. For production, prefer structured logs.
Example:
console.log(`[POST /api/friends/request] user=${userId} friend=${friendId}`);Standardize successful responses:
{
"success": true,
"data": {...}
}Error responses:
{
"success": false,
"error": "Message here"
}Always return proper HTTP status codes (e.g., 200, 201, 400, 401, 403, 500).
- Forgetting to handle
OPTIONSfor CORS - Not validating user sessions
- Missing return on error branch
- Overusing try-catch without logging
- Nesting too many dynamic folders unnecessarily
For more examples, explore files under
app/api/*/route.ts. Keep handlers stateless, secure, and deterministic.