import express from 'express';
import rateLimit from 'express-rate-limit';
const app = express();
// Rate limiting middleware
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per IP
message: 'Too many requests, please try again later!',
});
app.use('/api', limiter);
// Public route for blog posts
app.get('/api/posts', (req: Request, res: Response) => {
res.json({ posts: ['Post 1', 'Post 2'] });
});
app.listen(3000, () => console.log('Server running'));
API Security
/
Validation and Sanitisation
Validate
Sanitise
zod ...
// app/api/admin/post/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
// Define the schema for a blog post with Zod
const postSchema = z.object({
title: z.string().min(1, 'Title must not be empty').max(100, 'Title too long'),
content: z.string().min(10, 'Content too short'),
tags: z.array(z.string()).optional(), // Optional tags array
}).strict(); // No extra fields allowed
// POST handler for creating a blog post
export async function POST(req: NextRequest) {
try {
// Parse and validate the incoming JSON body
const body = await req.json();
const validatedData = postSchema.parse(body);
// Simulate saving to a database (in a real app, you'd use Prisma or similar)
const newPost = {
title: validatedData.title,
content: validatedData.content,
tags: validatedData.tags || [],
};
return NextResponse.json({ message: 'Post created', post: newPost }, { status: 201 });
} catch (error) {
if (error instanceof z.ZodError) {
// Return validation errors
return NextResponse.json({ errors: error.errors }, { status: 400 });
}
return NextResponse.json({ message: 'Server error' }, { status: 500 });
}
}
// Example client-side fetch to test it
/*
fetch('/api/admin/post', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'My First Post', content: 'Hello, world! This is a test post.' })
}).then(res => res.json()).then(console.log);
*/