API Routes (Маршруты API)
Примеры
Полезно знать: Если вы используете App Router, вместо API Routes можно использовать Server Components или Route Handlers.
API Routes предоставляют решение для создания публичного API с помощью Next.js.
Любой файл внутри папки pages/api
сопоставляется с /api/*
и будет обрабатываться как конечная точка API, а не как страница
. Эти файлы собираются только на стороне сервера и не увеличивают размер клиентского бандла.
Например, следующий API Route возвращает JSON-ответ с кодом состояния 200
:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
Полезно знать:
- API Routes не указывают заголовки CORS, что означает, что по умолчанию они работают только в пределах одного источника. Это поведение можно изменить, обернув обработчик запроса с помощью CORS request helpers.
- API Routes нельзя использовать с static exports. Однако Route Handlers в App Router поддерживают это.
- API Routes будут зависеть от конфигурации
pageExtensions
вnext.config.js
.
Параметры
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// ...
}
req
: Экземпляр http.IncomingMessageres
: Экземпляр http.ServerResponse
HTTP-методы
Для обработки различных HTTP-методов в API Route можно использовать req.method
в обработчике запроса:
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
// Обработка POST-запроса
} else {
// Обработка других HTTP-методов
}
}
export default function handler(req, res) {
if (req.method === 'POST') {
// Обработка POST-запроса
} else {
// Обработка других HTTP-методов
}
}
Вспомогательные функции запроса
API Routes предоставляют встроенные вспомогательные функции для разбора входящего запроса (req
):
req.cookies
- Объект, содержащий cookies, отправленные с запросом. По умолчанию{}
req.query
- Объект, содержащий строку запроса. По умолчанию{}
req.body
- Объект, содержащий тело запроса, разобранное поcontent-type
, илиnull
, если тело не было отправлено
Пользовательская конфигурация
Каждый API Route может экспортировать объект config
для изменения конфигурации по умолчанию:
export const config = {
api: {
bodyParser: {
sizeLimit: '1mb',
},
},
// Указывает максимально допустимое время выполнения функции (в секундах)
maxDuration: 5,
}
bodyParser
включен по умолчанию. Если вы хотите обрабатывать тело как Stream
или с помощью raw-body
, можно отключить его:
export const config = {
api: {
bodyParser: false,
},
}
Один из случаев отключения автоматического bodyParsing
— проверка сырого тела запроса вебхука, например от GitHub.
bodyParser.sizeLimit
— максимальный допустимый размер разбираемого тела в любом формате, поддерживаемом bytes:
export const config = {
api: {
bodyParser: {
sizeLimit: '500kb',
},
},
}
externalResolver
— явный флаг, указывающий серверу, что маршрут обрабатывается внешним резолвером, например express или connect. Включение этой опции отключает предупреждения о неразрешенных запросах.
export const config = {
api: {
externalResolver: true,
},
}
responseLimit
включен по умолчанию и выдает предупреждение, если тело ответа API Route превышает 4MB.
Если вы не используете Next.js в serverless-среде и понимаете последствия для производительности, можно отключить этот лимит:
export const config = {
api: {
responseLimit: false,
},
}
responseLimit
также может принимать число байтов или строку в формате, поддерживаемом bytes
, например 1000
, '500kb'
или '3mb'
. Это значение будет максимальным размером ответа перед появлением предупреждения. По умолчанию 4MB.
export const config = {
api: {
responseLimit: '8mb',
},
}
Вспомогательные функции ответа
Объект Server Response (часто сокращается до res
) включает набор вспомогательных методов, похожих на Express.js, для улучшения опыта разработки.
Доступные вспомогательные функции:
res.status(code)
- Устанавливает код состояния.code
должен быть допустимым HTTP-статусомres.json(body)
- Отправляет JSON-ответ.body
должен быть сериализуемым объектомres.send(body)
- Отправляет HTTP-ответ.body
может бытьстрокой
,объектом
илиBuffer
res.redirect([status,] path)
- Перенаправляет на указанный путь или URL.status
должен быть допустимым HTTP-статусом. Если не указан, по умолчанию используется "307" "Временное перенаправление".res.revalidate(urlPath)
- Ревалидация страницы по запросу с использованиемgetStaticProps
.urlPath
должен бытьстрокой
.
Установка кода состояния ответа
При отправке ответа клиенту можно установить код состояния.
Следующий пример устанавливает код состояния 200
(OK
) и возвращает JSON-ответ с сообщением:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
Отправка JSON-ответа
При отправке ответа клиенту можно отправить JSON-ответ, который должен быть сериализуемым объектом. В реальном приложении может потребоваться уведомить клиента о статусе запроса.
Следующий пример отправляет JSON-ответ с кодом 200
(OK
) и результатом асинхронной операции. Используется блок try-catch для обработки возможных ошибок:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const result = await someAsyncOperation()
res.status(200).json({ result })
} catch (err) {
res.status(500).json({ error: 'failed to load data' })
}
}
export default async function handler(req, res) {
try {
const result = await someAsyncOperation()
res.status(200).json({ result })
} catch (err) {
res.status(500).json({ error: 'failed to load data' })
}
}
Отправка HTTP-ответа
Отправка HTTP-ответа работает аналогично JSON-ответу. Разница в том, что тело ответа может быть строкой
, объектом
или Buffer
.
Следующий пример отправляет HTTP-ответ с кодом 200
(OK
) и результатом асинхронной операции:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const result = await someAsyncOperation()
res.status(200).send({ result })
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' })
}
}
export default async function handler(req, res) {
try {
const result = await someAsyncOperation()
res.status(200).send({ result })
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' })
}
}
Перенаправление на указанный путь или URL
Например, после отправки формы может потребоваться перенаправить клиента на указанный путь или URL.
Следующий пример перенаправляет клиента на /
при успешной отправке формы:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { name, message } = req.body
try {
await handleFormInputAsync({ name, message })
res.redirect(307, '/')
} catch (err) {
res.status(500).send({ error: 'Failed to fetch data' })
}
}
export default async function handler(req, res) {
const { name, message } = req.body
try {
await handleFormInputAsync({ name, message })
res.redirect(307, '/')
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' })
}
}
Добавление TypeScript-типов
Можно сделать API Routes более типобезопасными, импортируя типы NextApiRequest
и NextApiResponse
из next
, а также типизировав данные ответа:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
Полезно знать: Тело
NextApiRequest
имеет типany
, так как клиент может отправить любые данные. Перед использованием следует проверить тип/структуру тела во время выполнения.
Динамические API Routes
API Routes поддерживают динамические маршруты и следуют тем же правилам именования файлов, что и pages/
.
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { pid } = req.query
res.end(`Post: ${pid}`)
}
export default function handler(req, res) {
const { pid } = req.query
res.end(`Post: ${pid}`)
}
Теперь запрос к /api/post/abc
вернет текст: Post: abc
.
Catch all API routes
API Routes можно расширить для обработки всех путей, добавив три точки (...
) внутри скобок. Например:
pages/api/post/[...slug].js
соответствует/api/post/a
, а также/api/post/a/b
,/api/post/a/b/c
и т.д.
Полезно знать: Можно использовать имена, отличные от
slug
, например:[...param]
Сопоставленные параметры будут переданы как query-параметр (slug
в примере) и всегда будут массивом. Путь /api/post/a
будет иметь следующий объект query
:
{ "slug": ["a"] }
А для /api/post/a/b
и других соответствующих путей новые параметры будут добавлены в массив:
{ "slug": ["a", "b"] }
Пример:
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}
export default function handler(req, res) {
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}
Теперь запрос к /api/post/a/b/c
вернет текст: Post: a, b, c
.
Опциональные catch all API routes
Catch all маршруты можно сделать опциональными, заключив параметр в двойные скобки ([[...slug]]
).
Например, pages/api/post/[[...slug]].js
будет соответствовать /api/post
, /api/post/a
, /api/post/a/b
и т.д.
Основное отличие между catch all и опциональными catch all маршрутами в том, что опциональные соответствуют и маршруту без параметра (/api/post
в примере).
Объекты query
выглядят так:
{ } // GET `/api/post` (пустой объект)
{ "slug": ["a"] } // `GET /api/post/a` (массив с одним элементом)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (массив с несколькими элементами)
Особенности
- Предопределенные API Routes имеют приоритет над динамическими, а динамические — над catch all. Примеры:
pages/api/post/create.js
- Соответствует/api/post/create
pages/api/post/[pid].js
- Соответствует/api/post/1
,/api/post/abc
, но не/api/post/create
pages/api/post/[...slug].js
- Соответствует/api/post/1/2
,/api/post/a/b/c
, но не/api/post/create
,/api/post/abc
Потоковые ответы
Хотя Pages Router поддерживает потоковые ответы с API Routes, рекомендуется постепенно переходить на App Router и использовать Route Handlers, если вы используете Next.js 14+.
Пример потокового ответа из API Route с writeHead
:
import { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': "no-store",
})
let i = 0
while (i < 10) {
res.write(`data: ${i}\n\n`)
i++
await new Promise((resolve) => setTimeout(resolve, 1000))
}
res.end()
}