HTTP-запрос и проверка ответа API
Получаем данные по сети, проверяем их через Zod и показываем результат или ошибку.
Для Next.js 16.3.8 (App Router) и React 19.3.0, Zod 4.6.5. Обновлено .
В Next-02 афиша получала подготовленный массив, а функция readJson показывала HTTP-запрос отдельно. Теперь соединим запрос, проверку неизвестных данных и интерфейс. Для небольшого самостоятельного примера добавим страницу /news с учебными публикациями. Каталог /events и форму менять не нужно.
Используем JSONPlaceholder – учебный API с вымышленными данными. Его /posts возвращает публикации с id, title и body. Для GET-запроса не нужны регистрация и ключ. Это внешний сервис: без доступа к сети пример покажет ошибку.
Zod уже установлен на этапе форм. Сохраните lib/read-json.ts из статьи о получении данных. Следующие блоки – полные файлы, а не фрагменты для вставки внутрь существующего компонента.
Получение и проверка
import { z } from "zod";
import { readJson } from "./read-json";
export const newsSchema = z.array(
z.object({
id: z.number().int().positive(),
title: z.string().min(1),
body: z.string(),
}),
);
export type NewsItem = z.infer<typeof newsSchema>[number];
export async function loadNews(): Promise<NewsItem[]> {
const data: unknown = await readJson(
"https://jsonplaceholder.typicode.com/posts",
);
const result = newsSchema.safeParse(data);
if (!result.success) {
throw new Error("Источник вернул публикации неизвестного формата");
}
return result.data;
}Здесь две отдельные проверки. readJson проверяет HTTP-статус и читает JSON. newsSchema проверяет устройство полученного значения: массив ли это, есть ли нужные поля и подходят ли их типы. Ответ 200 с правильным JSON ещё не означает, что данные подходят приложению.
Схема выбирает только используемые поля; дополнительные свойства ответа не нужны для нашей страницы. Тип NewsItem получен из этой же схемы. Запись as NewsItem[] вместо проверки скрыла бы проблему от TypeScript, но не исправила бы данные.
Серверная страница
import { loadNews } from "@/lib/news";
export default async function NewsPage() {
const items = await loadNews();
return (
<main className="mx-auto max-w-3xl p-6">
<h1 className="mb-6 text-2xl font-semibold">Учебные публикации</h1>
{items.length === 0 ? (
<p>Публикаций пока нет.</p>
) : (
<ul className="grid gap-4">
{items.map((item) => (
<li key={item.id}>
<article className="border-border rounded-xl border p-4 break-words">
<h2 className="mb-2 text-lg font-semibold">{item.title}</h2>
<p>{item.body}</p>
</article>
</li>
))}
</ul>
)}
</main>
);
}Это серверный компонент: он дожидается проверенных данных и передаёт их в разметку. Не добавляйте сюда "use client". Обычный текст ответа выводится через JSX, без вставки полученного HTML.
Добавьте в существующую навигацию <Link href="/news">Публикации</Link>. Адрес /news также можно открыть напрямую.
Ожидание и ошибка
export default function Loading() {
return <p role="status">Загружаем публикации…</p>;
}"use client";
export default function ErrorPage({ retry }: { retry: () => void }) {
return (
<section role="alert">
<h2>Не удалось загрузить публикации</h2>
<p>Проверьте подключение и попробуйте ещё раз.</p>
<button type="button" onClick={() => retry()}>
Повторить
</button>
</section>
);
}Сбой сети, ошибочный HTTP-статус, неверный JSON и несовпадение со схемой приводят к сообщению о сбое. Пустой проверенный массив – успешный ответ без публикаций. Не подменяйте ошибку пустым массивом: иначе пользователь не отличит отсутствие данных от недоступности источника.
Проверьте разные ответы
Откройте /news, затем временно меняйте только получение data внутри loadNews:
| Случай | Что изменить | Ожидаемый результат |
|---|---|---|
| Правильный ответ | Оставить HTTP-запрос | Публикации из API |
| Пустой список | Вместо запроса написать const data: unknown = []; | «Публикаций пока нет» |
| Неправильная структура | Написать const data: unknown = [{ id: 1, title: null }]; | Интерфейс ошибки |
| HTTP-ошибка | В адресе запроса заменить /posts на /missing-resource | Интерфейс ошибки |
Это временные способы разобрать поведение, а не настройка рабочего источника. В режиме разработки Next.js может дополнительно открыть окно диагностики. После проверки восстановите HTTP-запрос и правильный адрес. Нажатие «Повторить» снова обращается к источнику; оно не исправляет неверный адрес или схему само по себе.
Краткая загрузка не обязана быть заметной при каждом переходе. Для её разбора можно временно добавить учебную задержку перед запросом, как в Next-02, а затем удалить её. Замедление сети в DevTools влияет на браузер, но не замедляет запрос от сервера Next.js к внешнему API. Подробнее – в статье о состояниях страницы.
Такую же последовательность применяют к настоящей афише: получают ответ, проверяют его по схеме своей модели и только затем передают данные карточкам. Подготовленный массив /events при этом остаётся полезным для локальных упражнений.
Документация: получение данных Next.js , Zod , JSONPlaceholder .