乐闻世界logo
搜索文章和话题

How do Next.js API Routes work?

2月17日 23:31

Next.js provides powerful API Routes functionality that allows developers to create API endpoints to handle server-side logic. API Routes can handle database queries, authentication, form submissions, and other server-side operations.

API Routes Basics

Creating an API Route

Create files in the pages/api directory, each file becomes an API endpoint.

shell
pages/ api/ hello.js → /api/hello users/ index.js → /api/users [id].js → /api/users/123

Basic Example

javascript
// pages/api/hello.js export default function handler(req, res) { res.status(200).json({ message: 'Hello from Next.js API!' }); }

Request and Response Objects

Request Object (req)

The req object contains the following properties:

  • req.method: HTTP method (GET, POST, PUT, DELETE, etc.)
  • req.query: Query parameters
  • req.body: Request body (POST, PUT, etc.)
  • req.headers: Request headers
  • req.cookies: Cookies

Response Object (res)

The res object provides the following methods:

  • res.status(code): Set status code
  • res.json(data): Send JSON response
  • res.send(data): Send response
  • res.redirect(url): Redirect
  • res.setHeader(name, value): Set response header

Handling Different HTTP Methods

javascript
// pages/api/users/[id].js export default async function handler(req, res) { const { id } = req.query; switch (req.method) { case 'GET': const user = await getUserById(id); res.status(200).json(user); break; case 'PUT': const updatedUser = await updateUser(id, req.body); res.status(200).json(updatedUser); break; case 'DELETE': await deleteUser(id); res.status(204).end(); break; default: res.setHeader('Allow', ['GET', 'PUT', 'DELETE']); res.status(405).end(`Method ${req.method} Not Allowed`); } }

Middleware

Custom Middleware

javascript
// lib/middleware.js export function authMiddleware(req, res, next) { const token = req.headers.authorization; if (!token) { return res.status(401).json({ error: 'Unauthorized' }); } // Verify token const user = verifyToken(token); if (!user) { return res.status(401).json({ error: 'Invalid token' }); } req.user = user; next(); }

Using Middleware

javascript
// pages/api/protected.js import { authMiddleware } from '@/lib/middleware'; export default function handler(req, res) { // Protected route res.status(200).json({ user: req.user }); } export const config = { api: { bodyParser: false, externalResolver: true, }, }; // In actual use, middleware needs to be called manually

Database Integration

Using Prisma

javascript
// pages/api/posts/index.js import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); export default async function handler(req, res) { if (req.method === 'GET') { const posts = await prisma.post.findMany(); res.status(200).json(posts); } else if (req.method === 'POST') { const post = await prisma.post.create({ data: req.body, }); res.status(201).json(post); } else { res.status(405).end(); } }

Using MongoDB

javascript
// pages/api/users/index.js import clientPromise from '@/lib/mongodb'; export default async function handler(req, res) { const client = await clientPromise; const db = client.db(); if (req.method === 'GET') { const users = await db.collection('users').find({}).toArray(); res.status(200).json(users); } else if (req.method === 'POST') { const result = await db.collection('users').insertOne(req.body); res.status(201).json(result); } else { res.status(405).end(); } }

Authentication

Using NextAuth.js

javascript
// pages/api/auth/[...nextauth].js import NextAuth from 'next-auth'; import Providers from 'next-auth/providers'; export default NextAuth({ providers: [ Providers.Google({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }), Providers.Credentials({ name: 'Credentials', credentials: { username: { label: "Username", type: "text" }, password: { label: "Password", type: "password" } }, authorize: async (credentials) => { // Verify user const user = await authenticate(credentials); if (user) { return user; } return null; } }), ], database: process.env.DATABASE_URL, });

JWT Verification

javascript
// lib/auth.js import jwt from 'jsonwebtoken'; export function verifyToken(token) { try { return jwt.verify(token, process.env.JWT_SECRET); } catch (error) { return null; } } export function createToken(payload) { return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1d' }); }

File Upload

javascript
// pages/api/upload.js import formidable from 'formidable'; import fs from 'fs'; import path from 'path'; export const config = { api: { bodyParser: false, }, }; export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).end(); } const form = formidable({ uploadDir: path.join(process.cwd(), '/public/uploads'), keepExtensions: true, }); form.parse(req, (err, fields, files) => { if (err) { return res.status(500).json({ error: 'File upload failed' }); } const file = files.file[0]; res.status(200).json({ url: `/uploads/${path.basename(file.filepath)}` }); }); }

Error Handling

javascript
// pages/api/error.js export default function handler(req, res) { try { // Business logic const data = processData(req.body); res.status(200).json(data); } catch (error) { console.error('API Error:', error); if (error.name === 'ValidationError') { res.status(400).json({ error: error.message }); } else if (error.name === 'UnauthorizedError') { res.status(401).json({ error: 'Unauthorized' }); } else { res.status(500).json({ error: 'Internal server error' }); } } }

CORS Configuration

javascript
// pages/api/cors.js export default function handler(req, res) { res.setHeader('Access-Control-Allow-Credentials', true); res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT'); res.setHeader( 'Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' ); if (req.method === 'OPTIONS') { res.status(200).end(); return; } res.status(200).json({ message: 'CORS enabled' }); }

Best Practices

  1. Use environment variables: Store sensitive information in .env files
  2. Validate input: Use validation libraries like Zod or Yup
  3. Error handling: Unified error handling format
  4. Logging: Record requests and error information
  5. Rate limiting: Prevent API abuse
  6. Caching: Cache frequently accessed data
  7. Documentation: Document APIs using Swagger or OpenAPI

Next.js API Routes provides a simple yet powerful way to build server-side APIs without needing a separate backend server, making full-stack development more convenient.

标签:Next.js