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.
- API Routes нельзя использовать с статическим экспортом. Однако Route Handlers в App Router поддерживают это.
- API Routes зависят от конфигурации
pageExtensionsвnext.config.js.
Параметры
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// ...
}req: Экземпляр http.IncomingMessage с добавлением предустановленных middlewareres: Экземпляр 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- Объект с куками, отправленными в запросе. По умолчанию{}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,
},
}Один из случаев отключения автоматического парсинга тела — проверка сырого тела вебхука, например от 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-среде и вы понимаете последствия отсутствия CDN или выделенного медиахоста, можно отключить лимит:
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может бытьstring,objectилиBufferres.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-ответу, но тело может быть string, object или 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
Например, после отправки формы может потребоваться перенаправить клиента на указанный путь.
Следующий пример перенаправляет клиента на / после успешной отправки формы:
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.
Перехват всех 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.
Опциональный перехват всех API Routes
Перехват всех маршрутов можно сделать опциональным, заключив параметр в двойные скобки ([[...slug]]).
Например, pages/api/post/[[...slug]].js совпадет с /api/post, /api/post/a, /api/post/a/b и т.д.
Основное отличие от обычного перехвата в том, что опциональный вариант совпадает и с маршрутом без параметра (/api/post).
Объекты query выглядят так:
{ } // GET `/api/post` (пустой объект)
{ "slug": ["a"] } // `GET /api/post/a` (массив с одним элементом)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (массив с несколькими элементами)Особенности
- Предопределенные API Routes имеют приоритет над динамическими, а динамические — над перехватывающими все. Примеры:
pages/api/post/create.js- Совпадет с/api/post/createpages/api/post/[pid].js- Совпадет с/api/post/1,/api/post/abc, но не с/api/post/createpages/api/post/[...slug].js- Совпадет с/api/post/1/2,/api/post/a/b/c, но не с/api/post/create,/api/post/abc
Edge API Routes
Если нужно использовать API Routes с Edge Runtime, рекомендуется постепенно переходить на App Router и использовать Route Handlers.
Сигнатура Route Handlers изоморфна, что позволяет использовать одну и ту же функцию для Edge и Node.js сред.