[Next.js Tutorial] API Routes: Xây dựng Backend nhanh chóng và hiệu quả

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.

API Routes trong Nextjs

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ư RequestResponse. Đ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!

Bài viết liên quan

[Next.js Tutorial] Dynamic Routes: Hướng dẫn cách dùng và cách tối ưu

Tìm hiểu cách tạo và quản lý Dynamic Routes trong Next.js (App Router). Bài viết hướng dẫn chi tiết từng bước, giúp bạn xây dựng các trang web động hiệu quả và chuẩn SEO.

[Next.js Tutorial] Data Fetching trong Server Components: Cách tối ưu hiệu quả

Tìm hiểu sâu về cách Data Fetching hoạt động với Server Components trong Next.js. Khám phá các phương pháp tốt nhất để truy vấn dữ liệu, tối ưu hiệu suất và xây dựng ứng dụng nhanh chóng, mượt mà hơn.

[Next.js Tutorial] Layouts: Hướng dẫn chi tiết để tối ưu giao diện Website

Bạn muốn quản lý giao diện website Next.js một cách linh hoạt và hiệu quả? Bài viết này sẽ hướng dẫn bạn cách sử dụng layouts để tăng tốc độ phát triển và cải thiện trải nghiệm người dùng.

[Next.js Tutorial] Navigation và Linking: Cách sử dụng cho hiệu suất tối ưu

Bài viết này sẽ giúp bạn làm chủ Navigation và Linking trong Next.js một cách dễ dàng. Tìm hiểu chi tiết cách sử dụng Next/link và useRouter để điều hướng trang, tối ưu hiệu suất ứng dụng của bạn.