ไทย

เรียนรู้วิธีสร้างแบ็กเอนด์ serverless ด้วย Next.js API Routes โดยตรงในแอปของคุณ คู่มือนี้ครอบคลุมตั้งแต่พื้นฐานถึงเทคนิคขั้นสูง เช่น การยืนยันตัวตนและฐานข้อมูล

Next.js API Routes: สร้างแบ็กเอนด์ของคุณอย่างง่ายดาย

Next.js ได้ปฏิวัติการพัฒนาส่วนหน้า (front-end) ด้วยฟีเจอร์ที่ทรงพลังและโครงสร้างที่เข้าใจง่าย แต่คุณรู้หรือไม่ว่ามันยังสามารถช่วยให้การพัฒนาส่วนหลัง (backend) ง่ายขึ้นอย่างมาก? Next.js API Routes ช่วยให้คุณสร้าง API endpoints แบบ serverless ได้โดยตรงภายในแอปพลิเคชัน Next.js ของคุณ ซึ่งช่วยลดความจำเป็นในการใช้เซิร์ฟเวอร์แบ็กเอนด์แยกต่างหากในหลายๆ กรณี คู่มือฉบับสมบูรณ์นี้จะแนะนำคุณตลอดกระบวนการสร้างแบ็กเอนด์ที่แข็งแกร่งและขยายขนาดได้โดยใช้ Next.js API Routes

Next.js API Routes คืออะไร?

API Routes คือฟังก์ชันแบบ serverless ที่คุณสร้างขึ้นภายในไดเรกทอรี /pages/api ในโปรเจกต์ Next.js ของคุณ ฟังก์ชันเหล่านี้จะจัดการคำขอ HTTP ที่เข้ามาและส่งคืนการตอบกลับ (responses) เช่นเดียวกับ API ของแบ็กเอนด์แบบดั้งเดิม ข้อแตกต่างที่สำคัญคือฟังก์ชันเหล่านี้จะถูกปรับใช้ (deploy) เป็นฟังก์ชันแบบ serverless ซึ่งหมายความว่าคุณไม่จำเป็นต้องจัดการเซิร์ฟเวอร์หรือโครงสร้างพื้นฐานใดๆ

ลองนึกภาพว่ามันคือฟังก์ชันแบ็กเอนด์ขนาดเล็กที่ทำงานตามความต้องการ (on-demand) และถูกรวมเข้ากับส่วนหน้าของ Next.js ของคุณได้อย่างราบรื่น

ข้อดีของการใช้ Next.js API Routes

เริ่มต้นใช้งาน Next.js API Routes

มาสร้าง API route ง่ายๆ ที่ส่งคืนการตอบกลับแบบ JSON กัน ก่อนอื่น ตรวจสอบให้แน่ใจว่าคุณได้ตั้งค่าโปรเจกต์ Next.js แล้ว หากยัง ให้สร้างโดยใช้คำสั่ง:

npx create-next-app my-app
cd my-app

จากนั้น สร้างไฟล์ชื่อ hello.js ภายในไดเรกทอรี /pages/api:

// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ name: 'สมชาย ใจดี' })
}

โค้ดนี้กำหนด API route ง่ายๆ ที่ตอบกลับด้วยอ็อบเจกต์ JSON ที่มีชื่อ "สมชาย ใจดี" หากต้องการเข้าถึง API route นี้ ให้เริ่มเซิร์ฟเวอร์สำหรับพัฒนา Next.js ของคุณ:

npm run dev

จากนั้น เปิดเบราว์เซอร์ของคุณและไปที่ http://localhost:3000/api/hello คุณควรจะเห็นการตอบกลับแบบ JSON ดังนี้:

{"name": "สมชาย ใจดี"}

ทำความเข้าใจเกี่ยวกับ API Route Handler

ฟังก์ชัน handler ใน API route ของคุณจะได้รับอาร์กิวเมนต์สองตัว:

คุณสามารถใช้อ็อบเจกต์เหล่านี้เพื่อจัดการกับคำขอประเภทต่างๆ, อ่านข้อมูลจากเนื้อหาของคำขอ, ตั้งค่าส่วนหัวของการตอบกลับ, และส่งการตอบกลับประเภทต่างๆ ได้

การจัดการ HTTP Methods ที่แตกต่างกัน

คุณสามารถใช้คุณสมบัติ req.method เพื่อตรวจสอบ HTTP method ของคำขอที่เข้ามาและจัดการกับเมธอดต่างๆ ตามความเหมาะสม ตัวอย่างเช่น:

// pages/api/method.js
export default function handler(req, res) {
  if (req.method === 'GET') {
    // จัดการคำขอแบบ GET
    res.status(200).json({ message: 'นี่คือคำขอแบบ GET' })
  } else if (req.method === 'POST') {
    // จัดการคำขอแบบ POST
    res.status(200).json({ message: 'นี่คือคำขอแบบ POST' })
  } else {
    // จัดการเมธอดอื่นๆ
    res.status(405).json({ message: 'Method Not Allowed' })
  }
}

ในตัวอย่างนี้ API route จะจัดการทั้งคำขอแบบ GET และ POST หากเมธอดของคำขอเป็น GET มันจะตอบกลับด้วยอ็อบเจกต์ JSON ที่มีข้อความ "นี่คือคำขอแบบ GET" หากเมธอดของคำขอเป็น POST มันจะตอบกลับด้วยอ็อบเจกต์ JSON ที่มีข้อความ "นี่คือคำขอแบบ POST" หากเป็นเมธอดอื่น ๆ มันจะตอบกลับด้วยข้อผิดพลาด 405 Method Not Allowed

การอ่านข้อมูลจาก Request Body

สำหรับคำขอแบบ POST, PUT, และ PATCH คุณมักจะต้องอ่านข้อมูลจาก request body Next.js มีการสนับสนุนในตัวสำหรับการแยกวิเคราะห์ (parsing) request body ที่เป็น JSON และ URL-encoded หากต้องการแยกวิเคราะห์ JSON request body คุณสามารถใช้คุณสมบัติ req.body ได้ ตัวอย่างเช่น:

// pages/api/post.js
export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email } = req.body

    // ประมวลผลข้อมูล
    console.log('Name:', name)
    console.log('Email:', email)

    res.status(200).json({ message: 'ได้รับข้อมูลเรียบร้อยแล้ว' })
  } else {
    res.status(405).json({ message: 'Method Not Allowed' })
  }
}

หากต้องการทดสอบ API route นี้ คุณสามารถใช้เครื่องมืออย่าง Postman หรือ curl เพื่อส่งคำขอแบบ POST พร้อมกับ body ที่เป็น JSON:

curl -X POST -H "Content-Type: application/json" -d '{"name": "สมหญิง จริงใจ", "email": "jane.doe@example.com"}' http://localhost:3000/api/post

การตั้งค่า Response Headers

คุณสามารถใช้เมธอด res.setHeader() เพื่อตั้งค่า response headers ซึ่งมีประโยชน์สำหรับการตั้งค่า content type, cache control และข้อมูลสำคัญอื่นๆ ตัวอย่างเช่น:

// pages/api/headers.js
export default function handler(req, res) {
  res.setHeader('Content-Type', 'application/json')
  res.setHeader('Cache-Control', 's-maxage=3600')
  res.status(200).json({ message: 'สวัสดีชาวโลก!' })
}

ในตัวอย่างนี้ API route จะตั้งค่า header Content-Type เป็น application/json เพื่อระบุว่าการตอบกลับเป็นอ็อบเจกต์ JSON และยังตั้งค่า header Cache-Control เป็น s-maxage=3600 ซึ่งจะบอกเบราว์เซอร์และ CDN ให้แคชการตอบกลับนี้นานสูงสุด 1 ชั่วโมง

การจัดการข้อผิดพลาด (Error Handling)

การจัดการข้อผิดพลาดอย่างเหมาะสมใน API routes ของคุณเป็นสิ่งสำคัญ คุณสามารถใช้ try-catch blocks เพื่อดักจับข้อยกเว้น (exceptions) และส่งการตอบกลับข้อผิดพลาดที่เหมาะสมไปยังไคลเอ็นต์ ตัวอย่างเช่น:

// pages/api/error.js
export default async function handler(req, res) {
  try {
    // จำลองการเกิดข้อผิดพลาด
    throw new Error('มีบางอย่างผิดพลาด')
  } catch (error) {
    console.error(error)
    res.status(500).json({ message: 'Internal Server Error' })
  }
}

ในตัวอย่างนี้ API route จำลองข้อผิดพลาดโดยการโยน (throw) อ็อบเจกต์ Error ใหม่ บล็อก catch จะดักจับข้อผิดพลาด, บันทึกลงในคอนโซล, และส่งการตอบกลับ 500 Internal Server Error ไปยังไคลเอ็นต์ ลองพิจารณาใช้ระบบบันทึกข้อมูล (logging system) ที่มีประสิทธิภาพ เช่น Sentry หรือ Datadog สำหรับสภาพแวดล้อมการใช้งานจริง (production)

การเชื่อมต่อกับฐานข้อมูล

หนึ่งในกรณีการใช้งานที่พบบ่อยที่สุดสำหรับ API routes คือการเชื่อมต่อกับฐานข้อมูล Next.js API Routes สามารถทำงานร่วมกับฐานข้อมูลต่างๆ ได้อย่างราบรื่น รวมถึง:

นี่คือตัวอย่างวิธีการเชื่อมต่อกับฐานข้อมูล MongoDB ใน Next.js API route:

// pages/api/mongodb.js
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {}

let client
let clientPromise

if (!process.env.MONGODB_URI) {
  throw new Error('โปรดเพิ่ม Mongo URI ของคุณใน .env.local')
}

if (process.env.NODE_ENV === 'development') {
  // ในโหมด development ให้ใช้ตัวแปรโกลบอลเพื่อให้ค่า
  // ถูกเก็บรักษาไว้เมื่อมีการรีโหลดโมดูลที่เกิดจาก HMR (Hot Module Replacement)
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options)
    global._mongoClientPromise = client.connect()
  }
  clientPromise = global._mongoClientPromise
} else {
  // ในโหมด production ไม่ควรใช้ตัวแปรโกลบอล
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

// ส่งออก MongoClient promise ที่มีขอบเขตของโมดูล การทำเช่นนี้ใน
// โมดูลที่แยกต่างหากจะช่วยให้สามารถนำ client กลับมาใช้ใหม่ได้อย่างปลอดภัยในหลายฟังก์ชัน
// ดูที่: https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js
export default async function handler(req, res) {
  try {
    const client = await clientPromise
    const db = client.db(process.env.MONGODB_DB)
    const collection = db.collection('users')

    const users = await collection.find({}).toArray()

    res.status(200).json({ users })
  } catch (e) {
    console.error(e)
    res.status(500).json({ message: 'ไม่สามารถดึงข้อมูลผู้ใช้ได้' })
  }
}

ก่อนที่จะรันโค้ดนี้ ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งแพ็กเกจ mongodb แล้ว:

npm install mongodb

คุณยังต้องตั้งค่าตัวแปรสภาพแวดล้อม MONGODB_URI และ MONGODB_DB ด้วย ตัวแปรเหล่านี้ควรถูกกำหนดไว้ในไฟล์ .env.local ของคุณ (หรือในการตั้งค่าตัวแปรสภาพแวดล้อมของผู้ให้บริการโฮสติ้งสำหรับ production) MONGODB_URI จะมี connection string สำหรับเชื่อมต่อกับฐานข้อมูล MongoDB ของคุณ และ MONGODB_DB จะระบุชื่อฐานข้อมูล

การยืนยันตัวตนและการให้สิทธิ์ (Authentication and Authorization)

การปกป้อง API routes ของคุณเป็นสิ่งสำคัญอย่างยิ่งเพื่อความปลอดภัย Next.js API Routes สามารถรักษาความปลอดภัยได้โดยใช้เทคนิคการยืนยันตัวตนและการให้สิทธิ์ต่างๆ รวมถึง:

นี่คือตัวอย่างวิธีการปกป้อง API route โดยใช้การยืนยันตัวตนแบบ JWT:

// pages/api/protected.js
import jwt from 'jsonwebtoken'

const secret = process.env.JWT_SECRET

export default function handler(req, res) {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    return res.status(401).json({ message: 'ไม่ได้รับอนุญาต' })
  }

  try {
    const decoded = jwt.verify(token, secret)
    // อ็อบเจกต์ "decoded" จะมีข้อมูลผู้ใช้ที่ฝังอยู่ใน token
    // ตัวอย่างเช่น: const userId = decoded.userId;

    // ดำเนินการกับคำขอต่อไป
    res.status(200).json({ message: 'เข้าถึงทรัพยากรที่ป้องกันไว้ได้สำเร็จ' })
  } catch (error) {
    return res.status(401).json({ message: 'Token ไม่ถูกต้อง' })
  }
}

ก่อนที่จะรันโค้ดนี้ ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งแพ็กเกจ jsonwebtoken แล้ว:

npm install jsonwebtoken

คุณยังต้องตั้งค่าตัวแปรสภาพแวดล้อม JWT_SECRET ด้วย นี่ควรเป็น secret key ที่แข็งแกร่งและสร้างขึ้นแบบสุ่ม ซึ่งใช้สำหรับลงนามและตรวจสอบ JWTs ควรเก็บสิ่งนี้ไว้อย่างปลอดภัยและห้ามเปิดเผยในโค้ดฝั่งไคลเอ็นต์ของคุณเด็ดขาด

Middleware

แม้ว่า Next.js จะไม่มี middleware แบบดั้งเดิมสำหรับ API routes ในลักษณะเดียวกับ Express.js แต่คุณสามารถบรรลุฟังก์ชันการทำงานที่คล้ายกันได้โดยการครอบ (wrapping) API route handlers ของคุณด้วยฟังก์ชันที่นำกลับมาใช้ใหม่ได้ ซึ่งช่วยให้คุณทำงานต่างๆ ได้เช่น:

นี่คือตัวอย่างวิธีการสร้าง middleware สำหรับการบันทึกข้อมูลแบบง่ายๆ:

// utils/middleware.js
export function withLogging(handler) {
  return async function(req, res) {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`)
    return handler(req, res)
  }
}

หากต้องการใช้ middleware นี้ เพียงแค่ครอบ API route handler ของคุณด้วยฟังก์ชัน withLogging:

// pages/api/logged.js
import { withLogging } from '../../utils/middleware'

async function handler(req, res) {
  res.status(200).json({ message: 'คำขอนี้ถูกบันทึกแล้ว' })
}

export default withLogging(handler)

แนวทางปฏิบัติที่ดีที่สุดสำหรับการสร้าง Next.js API Routes

เทคนิคขั้นสูง

Background Jobs

สำหรับงานที่ใช้เวลานานซึ่งไม่ควรบล็อกการตอบสนองของ API ให้พิจารณาใช้ background jobs คุณสามารถใช้ไลบรารีอย่าง BullMQ หรือ Bree เพื่อจัดการ background jobs ของคุณและประมวลผลแบบอะซิงโครนัส

WebSockets

สำหรับแอปพลิเคชันแบบเรียลไทม์ คุณสามารถใช้ WebSockets ใน Next.js API routes ของคุณได้ ไลบรารีอย่าง Socket.IO และ ws ทำให้การสร้างการเชื่อมต่อแบบถาวรระหว่างไคลเอ็นต์และเซิร์ฟเวอร์เป็นเรื่องง่าย

GraphQL

หากคุณต้องการวิธีที่ยืดหยุ่นและมีประสิทธิภาพมากขึ้นในการดึงข้อมูล ให้พิจารณาใช้ GraphQL คุณสามารถใช้ไลบรารีอย่าง Apollo Server หรือ Yoga เพื่อสร้าง GraphQL API endpoint ในแอปพลิเคชัน Next.js ของคุณ

สรุป

Next.js API Routes เป็นวิธีที่ทรงพลังและสะดวกในการสร้างแบ็กเอนด์แบบ serverless โดยตรงภายในแอปพลิเคชัน Next.js ของคุณ ด้วยการใช้ประโยชน์จากสถาปัตยกรรม serverless คุณสามารถทำให้การพัฒนาง่ายขึ้น ปรับปรุงประสิทธิภาพ และลดต้นทุน ไม่ว่าคุณจะสร้างฟอร์มติดต่อที่เรียบง่ายหรือแพลตฟอร์มอีคอมเมิร์ซที่ซับซ้อน Next.js API Routes สามารถช่วยให้คุณสร้างแบ็กเอนด์ที่แข็งแกร่งและขยายขนาดได้อย่างง่ายดาย ด้วยความเข้าใจที่มั่นคงในพื้นฐานและการประยุกต์ใช้แนวทางปฏิบัติที่ดีที่สุด คุณสามารถใช้ประโยชน์จากเครื่องมืออันทรงพลังนี้เพื่อสร้างแอปพลิเคชันที่มีประสิทธิภาพ ปลอดภัย และเข้าถึงได้ทั่วโลก