Погодный виджет лучше начать с API без секретного ключа и трёх явных состояний: загрузка, результат, ошибка. Вы превратите название города в координаты, запросите текущую температуру и не оставите пользователя перед пустой карточкой.
Запрос погоды состоит из двух шагов. Сначала геокодер ищет координаты по строке, затем прогноз использует широту и долготу. Такое разделение полезно: погода не обязана понимать, что означает «Казань», ей нужны числа.
Геокодер превращает город в координаты.
Погодный endpoint возвращает текущие значения.
Один renderState отвечает за загрузку, ошибку и готовую карточку.
Как устроен запрос погоды
Для учебного проекта используем Open-Meteo: отдельный геокодер и forecast endpoint. AbortController отменит предыдущий поиск, если пользователь быстро отправит новую форму. response.ok проверяется до response.json.
| Шаг | Вход | Результат |
|---|---|---|
| Геокодинг | Строка города | name, latitude, longitude |
| Прогноз | Координаты | temperature_2m, wind_speed_10m |
| Рендер | Данные или ошибка | Понятная карточка |
| Новый поиск | Сигнал AbortController | Старый запрос отменён |
После этого шага у каждой части есть одна роль. Интерфейс собирает действие, логика меняет состояние, а вывод показывает признак успеха. Это проще отлаживать, чем один большой обработчик.

Город сначала становится координатами. Новый поиск отменяет предыдущую цепочку
Пишем два fetch и обновление карточки
Функция requestJSON проверяет HTTP-статус. encodeURIComponent защищает query-параметр от пробелов и специальных символов. Ошибка AbortError не показывается пользователю: она означает, что её заменил более свежий запрос.
let controller;
async function requestJSON(url, signal){
const response=await fetch(url,{signal});
if(!response.ok) throw new Error('HTTP ' + response.status);
return response.json();
}
async function loadWeather(city){
controller?.abort(); controller=new AbortController();
showStatus('Загружаем…');
try{
const geo=await requestJSON(
'https://geocoding-api.open-meteo.com/v1/search?name=' + encodeURIComponent(city) + '&count=1&language=ru',
controller.signal
);
const place=geo.results?.[0];
if(!place) throw new Error('Город не найден');
const weather=await requestJSON(
'https://api.open-meteo.com/v1/forecast?latitude=' + place.latitude + '&longitude=' + place.longitude + '¤t=temperature_2m,wind_speed_10m&timezone=auto',
controller.signal
);
showWeather(place.name,weather.current);
}catch(error){
if(error.name!=='AbortError') showStatus(error.message==='Город не найден'?error.message:'Не удалось загрузить погоду');
}
}Название города кодируется перед URL. Старый поиск отменяется новым. HTTP-ошибка не маскируется под успешный JSON. Пустой результат и сетевой сбой получают разные понятные сообщения.

Код браузера виден всем. Сравнение показывает, какой вариант легче поддерживать и проверять.
Почему API-ключ нельзя спрятать во frontend
API-ключ, записанный в JavaScript браузера, увидит любой посетитель в исходниках и Network. Ограничения домена уменьшают риск, но не превращают ключ в секрет. Для платного или привилегированного API запрос нужно проводить через собственный backend.
| Состояние | Что видит пользователь | Что доступно |
|---|---|---|
| idle | Форма и пример города | Поиск |
| loading | Индикатор загрузки | Новая отправка отменяет старую |
| success | Город, температура, ветер | Повторный поиск |
| error | Понятное сообщение | Исправить запрос и повторить |
Сохраняйте в одном месте то, что может измениться. Если одно и то же значение скопировано в три функции, после первой правки они начнут расходиться. Один объект состояния и одна функция отрисовки снимают эту проблему.
Практика: проверяем ошибки и быстрый поиск
Проверьте нормальный город, строку с опечаткой, пустой ввод и отключённую сеть. Затем быстро отправьте два разных города. На экране должен остаться результат последнего запроса, а не того, который случайно ответил позже. Посмотрите ответ API в Network и сверьте единицы измерения. Не добавляйте знак градуса или скорость ветра по памяти, если сервис уже прислал точную подпись. Повторите поиск города с одинаковым названием в разных странах. Если интерфейс показывает только первое совпадение, добавьте страну или регион в подпись, чтобы пользователь понимал, какие координаты выбраны.
- Найдите свой город кириллицей.
- Введите набор случайных символов.
- Отключите сеть в DevTools.
- Быстро отправьте Москва, затем Казань.
- Проверьте карточку на 320 пикселях.
- Добавьте единицы измерения из ответа API.
Пустой запрос не уходит в сеть. Город с пробелом корректно кодируется. Быстрый второй поиск отменяет первый. Загрузка, ошибка и успех выглядят как разные состояния.

Пустого экрана быть не должно. Пройдите все четыре сценария перед публикацией проекта.
Доводим погодный виджет до готового состояния
После текущей погоды добавьте прогноз на три дня и сохранение последнего города. Перед этим вынесите преобразование weather code в отдельную функцию и протестируйте неизвестный код. Интерфейс не должен зависеть от идеального ответа API.
Ответ 404 пытаются читать как успех.
Его можно увидеть и использовать.
Пустая карточка кажется сломанной.
Старый ответ перезаписывает новый.
Что получится в итоге

Готовая погодная карточка показывает город, температуру, состояние, влажность и ветер, а поиск честно сообщает о загрузке и ошибке.
Зачем сначала искать координаты?
Погодный endpoint принимает широту и долготу, а не произвольное название.
Можно ли спрятать ключ во frontend?
Нет, код и сетевые запросы видны пользователю.
Зачем AbortController?
Чтобы старый медленный ответ не заменил результат нового поиска.
Как понять, что проект готов?
Он повторяет целевой сценарий несколько раз подряд, понятно реагирует на ошибочный ввод и не теряет состояние при обычных действиях.
Можно ли копировать код целиком?
Можно как стартовую точку, но сначала замените значения из примера, затем запустите проект по шагам. Если вы не можете объяснить одну строку, её лучше разобрать до следующего шага.
Асинхронность и DOM разбираются в курсе JavaScript. Основу запроса закрепите по гайду Fetch API.
Если браузер блокирует запрос, сравните ситуацию со статьёй о CORS. Для карточки пригодится переключение темы. В Кодике удобно подменять города и проверять все состояния по очереди.