Build your API endpoints with Next.js API routes
Create simple API endpoints with Next.js
// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'GET') {
return res.status(405).json({
name: 'Method Not Allowed',
message: 'Only GET requests are allowed'
})
}
res.status(200).json({
name: 'John Doe',
message: 'Hello from Next.js!'
})
}
// pages/api/cors-example.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import Cors from 'cors'
// Initialize the cors middleware
const cors = Cors({
methods: ['GET', 'POST', 'OPTIONS'],
})
// Helper method to wait for middleware
function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) {
return new Promise((resolve, reject) => {
fn(req, res, (result: any) => {
if (result instanceof Error) {
return reject(result)
}
return resolve(result)
})
})
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// Run the middleware
await runMiddleware(req, res, cors)
// Set custom headers
res.setHeader('Cache-Control', 's-maxage=86400')
// Rest of the API logic
res.json({ message: 'This is a CORS-enabled endpoint' })
}
Create dynamic API endpoints with route parameters
// pages/api/posts/[id].ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { prisma } from '../../../lib/prisma'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { id } = req.query
switch (req.method) {
case 'GET':
try {
const post = await prisma.post.findUnique({
where: { id: String(id) }
})
if (!post) {
return res.status(404).json({ message: 'Post not found' })
}
return res.status(200).json(post)
} catch (error) {
return res.status(500).json({ message: 'Error fetching post' })
}
case 'PUT':
try {
const updatedPost = await prisma.post.update({
where: { id: String(id) },
data: req.body
})
return res.status(200).json(updatedPost)
} catch (error) {
return res.status(500).json({ message: 'Error updating post' })
}
case 'DELETE':
try {
await prisma.post.delete({
where: { id: String(id) }
})
return res.status(204).end()
} catch (error) {
return res.status(500).json({ message: 'Error deleting post' })
}
default:
res.setHeader('Allow', ['GET', 'PUT', 'DELETE'])
return res.status(405).json({ message: `Method ${req.method} Not Allowed` })
}
}
// pages/api/posts/[...slug].ts
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { slug } = req.query
// slug will be an array of path segments
// e.g. /api/posts/2023/01/hello -> ['2023', '01', 'hello']
res.status(200).json({
slug: slug,
path: slug.join('/'),
query: req.query
})
}
Add middleware to your API routes
// middleware/withAuth.ts
import { NextApiRequest, NextApiResponse } from 'next'
import { getToken } from 'next-auth/jwt'
export function withAuth(handler: any) {
return async (req: NextApiRequest, res: NextApiResponse) => {
try {
const token = await getToken({ req })
if (!token) {
return res.status(401).json({
error: 'Unauthorized'
})
}
// Add user to request object
req.user = token
// Call the original handler
return handler(req, res)
} catch (error) {
return res.status(500).json({
error: 'Authentication error'
})
}
}
}
// Usage in API route
import { withAuth } from '../../../middleware/withAuth'
export default withAuth(async function handler(req, res) {
// This route is now protected
const user = req.user
res.json({ message: `Hello ${user.name}!` })
})
// middleware/rateLimit.ts
import rateLimit from 'express-rate-limit'
import { NextApiRequest, NextApiResponse } from 'next'
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
})
export function withRateLimit(handler: any) {
return async (req: NextApiRequest, res: NextApiResponse) => {
try {
await new Promise((resolve, reject) => {
limiter(req, res, (result: any) => {
if (result instanceof Error) {
return reject(result)
}
resolve(result)
})
})
return handler(req, res)
} catch (error) {
return res.status(429).json({
error: 'Too Many Requests'
})
}
}
}