Дізнайтеся, як використовувати API-маршрути Next.js для створення безсерверних бекендів безпосередньо у вашому додатку Next.js. Цей посібник охоплює все, від базових налаштувань до передових методів автентифікації, збереження даних тощо.
API-маршрути Next.js: Легка розробка вашого бекенду
Next.js здійснив революцію у фронтенд-розробці завдяки своїм потужним функціям та інтуїтивно зрозумілій структурі. Але чи знали ви, що він також може значно спростити розробку бекенду? API-маршрути Next.js дозволяють створювати безсерверні API-ендпоінти безпосередньо у вашому додатку Next.js, у багатьох випадках усуваючи потребу в окремому бекенд-сервері. Цей вичерпний посібник проведе вас через процес створення надійного та масштабованого бекенду за допомогою API-маршрутів Next.js.
Що таке API-маршрути Next.js?
API-маршрути — це безсерверні функції, які ви створюєте у каталозі /pages/api
вашого проєкту Next.js. Ці функції обробляють вхідні HTTP-запити та повертають відповіді, так само як і традиційний бекенд-API. Ключова відмінність полягає в тому, що вони розгортаються як безсерверні функції, що означає, що вам не потрібно керувати серверами чи інфраструктурою.
Уявляйте їх як легковагі бекенд-функції на вимогу, які безшовно інтегровані з вашим фронтендом на Next.js.
Переваги використання API-маршрутів Next.js
- Спрощена розробка: Пишіть код для фронтенду та бекенду в одному проєкті, використовуючи JavaScript або TypeScript. Більше не потрібно перемикатися між різними проєктами та технологіями.
- Безсерверна архітектура: Скористайтеся перевагами масштабованості, надійності та економічності безсерверних обчислень. Платіть лише за ресурси, які споживаєте.
- Легке розгортання: Розгортайте весь ваш додаток (фронтенд і бекенд) однією командою за допомогою платформ, таких як Vercel або Netlify.
- Вбудована безпека: Next.js та безсерверні платформи надають вбудовані функції безпеки для захисту ваших API-ендпоінтів.
- Покращена продуктивність: API-маршрути можуть бути розгорнуті ближче до ваших користувачів, що зменшує затримку та покращує продуктивність, що особливо корисно для користувачів у всьому світі.
- Повторне використання коду: Діліться кодом між вашим фронтендом та бекендом, зменшуючи дублювання коду та покращуючи його підтримку.
Початок роботи з API-маршрутами Next.js
Створімо простий API-маршрут, який повертає відповідь у форматі 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: 'John Doe' })
}
Цей код визначає простий API-маршрут, який відповідає об'єктом JSON, що містить ім'я "John Doe". Щоб отримати доступ до цього API-маршруту, запустіть сервер розробки Next.js:
npm run dev
Потім відкрийте браузер і перейдіть за адресою http://localhost:3000/api/hello
. Ви повинні побачити таку відповідь у форматі JSON:
{"name": "John Doe"}
Розуміння обробника API-маршруту
Функція handler
у вашому API-маршруті отримує два аргументи:
req
: екземплярhttp.IncomingMessage
, який містить інформацію про вхідний запит, таку як метод запиту, заголовки та тіло.res
: екземплярhttp.ServerResponse
, який дозволяє вам надіслати відповідь клієнту.
Ви можете використовувати ці об'єкти для обробки різних типів запитів, читання даних з тіла запиту, встановлення заголовків відповіді та надсилання різних типів відповідей.
Обробка різних методів HTTP
Ви можете використовувати властивість req.method
для визначення методу HTTP вхідного запиту та відповідної обробки різних методів. Наприклад:
// 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: 'Метод не дозволено' })
}
}
У цьому прикладі API-маршрут обробляє як GET, так і POST запити. Якщо метод запиту — GET, він відповідає об'єктом JSON з повідомленням "Це GET-запит". Якщо метод запиту — POST, він відповідає об'єктом JSON з повідомленням "Це POST-запит". Якщо метод запиту — будь-який інший, він відповідає помилкою 405 Метод не дозволено.
Читання даних з тіла запиту
Для запитів POST, PUT та PATCH часто потрібно читати дані з тіла запиту. Next.js надає вбудовану підтримку для парсингу тіл запитів у форматах JSON та URL-encoded. Щоб розпарсити тіло JSON-запиту, ви можете використовувати властивість 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: 'Метод не дозволено' })
}
}
Щоб протестувати цей API-маршрут, ви можете використати інструмент, такий як Postman або curl, щоб надіслати POST-запит з тілом у форматі JSON:
curl -X POST -H "Content-Type: application/json" -d '{"name": "Олена Петренко", "email": "olena.petrenko@example.com"}' http://localhost:3000/api/post
Встановлення заголовків відповіді
Ви можете використовувати метод res.setHeader()
для встановлення заголовків відповіді. Це корисно для встановлення типу вмісту, контролю кешування та іншої важливої інформації. Наприклад:
// 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-маршрут встановлює заголовок Content-Type
на application/json
, вказуючи, що відповідь є об'єктом JSON. Він також встановлює заголовок Cache-Control
на s-maxage=3600
, що повідомляє браузеру та CDN кешувати відповідь до 1 години.
Обробка помилок
Важливо грамотно обробляти помилки у ваших API-маршрутах. Ви можете використовувати блоки try-catch для перехоплення винятків та надсилання відповідних повідомлень про помилки клієнту. Наприклад:
// 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: 'Внутрішня помилка сервера' })
}
}
У цьому прикладі API-маршрут симулює помилку, кидаючи новий об'єкт Error
. Блок catch перехоплює помилку, записує її в консоль і надсилає клієнту відповідь 500 Internal Server Error. Для виробничих середовищ розгляньте можливість використання надійної системи логування, такої як Sentry або Datadog.
Підключення до бази даних
Одним з найпоширеніших випадків використання API-маршрутів є підключення до бази даних. API-маршрути Next.js безшовно інтегруються з різними базами даних, зокрема:
- MongoDB: популярна NoSQL база даних, яка добре підходить для гнучких та неструктурованих даних.
- PostgreSQL: потужна реляційна база даних з відкритим кодом, відома своєю надійністю та цілісністю даних.
- MySQL: ще одна популярна реляційна база даних з відкритим кодом, що широко використовується для веб-додатків.
- Firebase: хмарна платформа, що надає базу даних реального часу та інші послуги.
- FaunaDB: безсерверна база даних, розроблена для глобальних додатків.
Ось приклад підключення до бази даних MongoDB в API-маршруті Next.js:
// 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') {
// У режимі розробки використовуйте глобальну змінну, щоб значення
// зберігалося між перезавантаженнями модуля, спричиненими HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// У виробничому режимі краще не використовувати глобальну змінну.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Експортуйте проміс MongoClient на рівні модуля. Роблячи це в
// окремому модулі, клієнт можна безпечно використовувати повторно в кількох
// функціях. Див.: 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
(або в налаштуваннях змінних середовища вашого хостинг-провайдера для виробництва). MONGODB_URI
містить рядок підключення до вашої бази даних MongoDB, а MONGODB_DB
вказує назву бази даних.
Автентифікація та авторизація
Захист ваших API-маршрутів є критично важливим для безпеки. API-маршрути Next.js можна захистити за допомогою різних технік автентифікації та авторизації, зокрема:
- JSON Web Tokens (JWT): стандарт для безпечної передачі інформації між сторонами у вигляді об'єкта JSON.
- API-ключі: простий спосіб обмежити доступ до ваших API-ендпоінтів.
- OAuth: протокол делегування, який дозволяє користувачам надавати стороннім додаткам доступ до своїх ресурсів без передачі облікових даних.
- NextAuth.js: повне рішення для автентифікації з відкритим кодом для додатків Next.js.
Ось приклад того, як захистити API-маршрут за допомогою 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" містить інформацію про користувача, вбудовану в токен
// Наприклад: const userId = decoded.userId;
// Продовжити обробку запиту
res.status(200).json({ message: 'Доступ до захищеного ресурсу отримано успішно' })
} catch (error) {
return res.status(401).json({ message: 'Недійсний токен' })
}
}
Перед запуском цього коду переконайтеся, що у вас встановлений пакет jsonwebtoken
:
npm install jsonwebtoken
Вам також потрібно встановити змінну середовища JWT_SECRET
. Це має бути сильний, випадково згенерований секретний ключ, який використовується для підпису та перевірки JWT. Зберігайте його в безпеці та ніколи не розкривайте у вашому клієнтському коді.
Проміжне програмне забезпечення (Middleware)
Хоча Next.js не пропонує традиційне проміжне програмне забезпечення (middleware) для API-маршрутів так, як це робить Express.js, ви можете досягти схожої функціональності, обгортаючи ваші обробники API-маршрутів у функції, що можна використовувати повторно. Це дозволяє виконувати такі завдання, як:
- Автентифікація: перевірка облікових даних користувача перед наданням доступу до API-ендпоінтів.
- Авторизація: перевірка, чи має користувач необхідні дозволи для виконання певної дії.
- Логування: запис вхідних запитів та вихідних відповідей для аудиту та налагодження.
- Валідація: перевірка даних запиту на відповідність певним критеріям.
- Обмеження частоти запитів: захист вашого API від зловживань шляхом обмеження кількості запитів, які користувач може зробити за певний проміжок часу.
Ось приклад створення простого проміжного ПЗ для логування:
// 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)
}
}
Щоб використати це проміжне ПЗ, просто оберніть ваш обробник API-маршруту функцією withLogging
:
// pages/api/logged.js
import { withLogging } from '../../utils/middleware'
async function handler(req, res) {
res.status(200).json({ message: 'Цей запит було залоговано' })
}
export default withLogging(handler)
Найкращі практики для створення API-маршрутів Next.js
- Зберігайте ваші API-маршрути невеликими та сфокусованими. Кожен API-маршрут повинен обробляти конкретне завдання або ресурс.
- Використовуйте змінні середовища для чутливих даних. Ніколи не вписуйте секрети або API-ключі безпосередньо в код.
- Валідуйте дані запиту, щоб запобігти вразливостям безпеки. Використовуйте бібліотеки, такі як Joi або Yup, для валідації тіла запиту.
- Грамотно обробляйте помилки та надавайте інформативні повідомлення про них. Використовуйте блоки try-catch та логуйте помилки в централізоване місце.
- Використовуйте кешування для покращення продуктивності. Кешуйте дані, до яких часто звертаються, щоб зменшити навантаження на базу даних.
- Моніторте ваші API-маршрути на предмет продуктивності та помилок. Використовуйте інструменти моніторингу, такі як Sentry або Datadog, для відстеження стану вашого API.
- Документуйте ваші API-маршрути за допомогою інструментів, таких як Swagger або OpenAPI. Це полегшує іншим розробникам використання вашого API.
- Розгляньте можливість використання TypeScript для типізації. TypeScript може допомогти вам виявляти помилки на ранніх етапах та покращити підтримку вашого коду.
- Думайте про інтернаціоналізацію (i18n) з самого початку. Якщо ваш додаток буде використовуватися користувачами з різних країн, проєктуйте ваші API-маршрути для підтримки кількох мов та валют. Наприклад, API-ендпоінти для електронної комерції можуть потребувати обробки різних податкових ставок та вартості доставки залежно від місцезнаходження користувача.
- Впровадьте належну конфігурацію CORS (Cross-Origin Resource Sharing). Це критично важливо, коли до вашого API звертаються з домену, відмінного від домену вашого додатку Next.js. Ретельно налаштуйте CORS, щоб дозволити доступ до ресурсів вашого API лише авторизованим джерелам.
Просунуті техніки
Фонові завдання
Для довготривалих завдань, які не повинні блокувати відповідь API, розгляньте використання фонових завдань. Ви можете використовувати бібліотеки, такі як BullMQ або Bree, для керування фоновими завданнями та їх асинхронної обробки.
Вебсокети
Для додатків реального часу ви можете використовувати вебсокети у ваших API-маршрутах Next.js. Бібліотеки, такі як Socket.IO та ws, полегшують встановлення постійних з'єднань між клієнтом та сервером.
GraphQL
Якщо вам потрібен більш гнучкий та ефективний спосіб отримання даних, розгляньте використання GraphQL. Ви можете використовувати бібліотеки, такі як Apollo Server або Yoga, для створення GraphQL API-ендпоінту у вашому додатку Next.js.
Висновок
API-маршрути Next.js надають потужний та зручний спосіб створення безсерверних бекендів безпосередньо у вашому додатку Next.js. Використовуючи переваги безсерверної архітектури, ви можете спростити розробку, покращити продуктивність та зменшити витрати. Незалежно від того, чи створюєте ви просту контактну форму, чи складну платформу для електронної комерції, API-маршрути Next.js допоможуть вам легко створити надійний та масштабований бекенд. Маючи тверде розуміння основ та застосовуючи найкращі практики, ви зможете використовувати цей потужний інструмент для створення ефективних, безпечних та глобально доступних додатків.