Bạn đã bao giờ mơ về một thế giới nơi frontend và backend chung sống hòa thuận dưới một mái nhà, nơi việc xây dựng một API đầy đủ chức năng cũng đơn giản như tạo một component React? Giấc mơ đó đã trở thành hiện thực với API Routes trong Next.js, đặc biệt là với sự ra đời của App Router.
Trong bài viết này, hãy cùng nhau khám phá cách Next.js biến đổi hoàn toàn cuộc chơi phát triển web, cho phép bạn xây dựng các ứng dụng full-stack mạnh mẽ, hiệu suất cao mà không cần rời khỏi hệ sinh thái quen thuộc.
API Routes là gì? Tại sao bạn nên quan tâm?
Hiểu một cách đơn giản, API Routes là một tính năng của Next.js cho phép bạn tạo các điểm cuối (endpoints) API ngay bên trong dự án Next.js của mình. Thay vì phải thiết lập một máy chủ backend riêng biệt (sử dụng Express, Spring, Django, etc.), bạn có thể viết mã phía máy chủ để xử lý các yêu cầu HTTP (GET, POST, PUT, DELETE), tương tác với cơ sở dữ liệu, xác thực người dùng, và thực hiện bất kỳ logic backend nào khác.
Với App Router, kiến trúc này được tinh chỉnh và trở nên mạnh mẽ hơn bao giờ hết thông qua một khái niệm gọi là Route Handlers.
Lợi ích vượt trội:
- Tất cả trong một (All-in-One): Đơn giản hóa kiến trúc dự án. Frontend và backend cùng chung một mã nguồn, một quy trình build và triển khai.
- Hiệu suất tối ưu: Các API Routes có thể tận dụng môi trường Serverless Functions khi triển khai trên các nền tảng như Vercel, giúp tự động co giãn theo lưu lượng truy cập và tiết kiệm chi phí.
- Trải nghiệm lập trình viên (DX) tuyệt vời: Bạn vẫn sử dụng JavaScript/TypeScript và các công cụ quen thuộc trong hệ sinh thái React/Next.js.
- Bảo mật: Mã nguồn backend của bạn không bao giờ được gửi đến trình duyệt, giúp bảo vệ các thông tin nhạy cảm như API key hay chuỗi kết nối cơ sở dữ liệu (database connection string).
Tạo API đầu tiên với Route Handlers
Trong App Router, việc tạo một API endpoint trở nên trực quan hơn bao giờ hết. Thay vì các file trong thư mục pages/api
, chúng ta tạo các file route.js
(hoặc route.ts
) bên trong các thư mục app
.
Cấu trúc thư mục
Để tạo một endpoint /api/hello
, bạn chỉ cần tạo cấu trúc thư mục sau:
app/
└── api/
└── hello/
└── route.js
Viết Route Handler
Bên trong file route.js
, bạn xuất (export) các hàm được đặt tên theo các phương thức HTTP.
// In app/api/hello/route.js
// Hàm xử lý cho phương thức GET
export async function GET(request) {
// Logic xử lý ở đây
return new Response('Chào mừng bạn đến với API của tôi!', {
status: 200,
})
}
// Hàm xử lý cho phương thức POST
export async function POST(request) {
const body = await request.json() // Đọc body của request
console.log(body)
return new Response(
JSON.stringify({ message: 'Dữ liệu đã được nhận', data: body }),
{
status: 201, // Created
headers: {
'Content-Type': 'application/json',
},
},
)
}
Thật đơn giản phải không? Chỉ với vài dòng code, bạn đã có một API endpoint /api/hello
sẵn sàng nhận các yêu cầu GET và POST.
Lưu ý quan trọng: Next.js xây dựng trên các Web API chuẩn như Request
và Response
. Điều này giúp mã của bạn dễ dàng tương thích và chạy được trên các môi trường khác nhau, ví dụ như Edge Functions.
Các kỹ thuật nâng cao và Ví dụ thực tế
1. Dynamic API Routes: Tạo API Linh Hoạt
Giống như dynamic pages, bạn có thể tạo các API route động để xử lý các tham số thay đổi. Ví dụ, để lấy thông tin một sản phẩm cụ thể qua /api/products/[id]
.
Cấu trúc thư mục:
app/
└── api/
└── products/
└── [id]/
└── route.js
Mã nguồn (route.js
):
// In app/api/products/[id]/route.js
export async function GET(request, { params }) {
const productId = params.id // Lấy 'id' từ URL
// Ví dụ: Tìm sản phẩm trong cơ sở dữ liệu
// const product = await db.products.find(productId);
return new Response(
JSON.stringify({ id: productId, name: `Sản phẩm ${productId}` }),
{
status: 200,
headers: {
'Content-Type': 'application/json',
},
},
)
}
Giờ đây, một yêu cầu đến /api/products/123
sẽ được xử lý bởi handler này và params.id
sẽ có giá trị là "123"
.
2. Xử lý Request và Response
Tóm tắt các đầu mục:
- Truy cập Query Parameters:
const { searchParams } = new URL(request.url)
- Đọc Headers:
const authorization = request.headers.get('authorization')
- Đọc Cookies: Sử dụng
cookies()
từnext/headers
. - Thiết lập Headers cho Response:
new Response(..., { headers: { ... } })
- Thiết lập Cookies cho Response:
new Response(..., { headers: { 'Set-Cookie': '...' } })
- Chuyển hướng (Redirect): Sử dụng
NextResponse.redirect()
từnext/server
.
Ví dụ tổng hợp:
// In app/api/search/route.js
import { NextResponse } from 'next/server'
export async function GET(request) {
const { searchParams } = new URL(request.url)
const query = searchParams.get('q') // Lấy query param 'q'
if (!query) {
return new NextResponse(
JSON.stringify({ error: 'Thiếu tham số tìm kiếm' }),
{
status: 400,
headers: { 'Content-Type': 'application/json' },
},
)
}
// Logic tìm kiếm với 'query'
const results = [`Kết quả 1 cho "${query}"`, `Kết quả 2 cho "${query}"`]
return NextResponse.json({ data: results }) // Cách trả về JSON tiện lợi
}
3. Caching và Revalidating
Một trong những sức mạnh lớn nhất của Next.js là khả năng caching. Mặc định, các yêu cầu GET
trong Route Handlers sẽ được cache lại. Bạn có thể kiểm soát hành vi này:
- Tắt cache:
export const dynamic = 'force-dynamic'
- Revalidate theo thời gian:
export async function GET(request) { const res = await fetch('https://api.example.com/data', { next: { revalidate: 3600 }, // Revalidate mỗi giờ }) const data = await res.json() return NextResponse.json(data) }
Điều này cực kỳ hữu ích để xây dựng các API hiệu suất cao mà không cần phải gọi đến nguồn dữ liệu (database, CMS) mỗi lần có yêu cầu.
Khi nào nên sử dụng API Routes?
Những tình huống phổ biến nhất trong thực tế:
- Xử lý Form: Nhận dữ liệu từ form phía client, xác thực và lưu vào cơ sở dữ liệu.
- Giao tiếp với bên thứ ba: Che giấu API key bằng cách tạo một endpoint của riêng bạn để gọi đến API của bên thứ ba (Stripe, SendGrid, v.v.).
- Xác thực người dùng: Xử lý đăng nhập, đăng ký, và quản lý session.
- Cung cấp dữ liệu cho Client Components: Tạo các API endpoint để các component phía client có thể fetch dữ liệu một cách an toàn.
- Xây dựng một Backend hoàn chỉnh: Với các dự án vừa và nhỏ, API Routes hoàn toàn có thể thay thế một backend riêng biệt, giúp bạn tiết kiệm thời gian và công sức.
Kết luận: Tương lai của phát triển Full-Stack
API Routes với App Router không chỉ là một tính năng; đó là một sự thay đổi trong tư duy về cách chúng ta xây dựng ứng dụng web. Bằng cách xóa bỏ ranh giới giữa frontend và backend, Next.js trao quyền cho các nhà phát triển để tạo ra các sản phẩm hoàn chỉnh, hiệu suất cao và dễ bảo trì hơn bao giờ hết. Dù bạn đang xây dựng một trang blog cá nhân hay một ứng dụng thương mại điện tử phức tạp, hãy thử sức với API Routes. Bạn sẽ ngạc nhiên về tốc độ và sự tiện lợi mà nó mang lại.
Bây giờ, bạn đã sẵn sàng để xây dựng backend của riêng mình ngay trong Next.js chưa? Hãy bắt đầu ngay hôm nay!