Мы все одержимы погодой. «Как будет завтра?», «Какая погода будет на выходных? У меня пикник»... Ночью, в новостях, мы обычно больше внимания уделяем разделу прогноза, чем любому другому разделу. Мы хотим знать, будет ли дождь, или будет солнечный день, или чего ожидать на следующий день, я думаю, такова человеческая природа, мы хотим все спланировать и все держать под контролем.

Вот почему я решил создать погодное приложение на JS с использованием WeatherOpenMap API. Прежде чем перейти к различным шагам, которые я выполнил для его создания, вы должны иметь общее представление о том, как работать с API и асинхронными функциями, вам это понадобится!

Следуйте за мной, и я покажу вам, как это сделать.

В первую очередь рекомендуется ознакомиться с Документацией WeatherOpenMap, здесь вы найдете все услуги, которые они предоставляют, и способы их использования. Базовая услуга предоставляется бесплатно, взамен они будут отслеживать, кто запрашивает данные, которые они обслуживают, и сколько данных они запрашивают. Причина, по которой они это делают, заключается в том, что люди не могут воспользоваться их услугами. Запуск серверов, особенно больших, стоит денег, и хотя каждый текущий запрос погоды (или что-то еще) относительно дешев, если количество запросов становится слишком большим, стоимость может быть значительной. Для нашего приложения мы будем использовать бесплатный сервис, и, если наш сайт станет известным, мы обновим его. Их бесплатный план позволяет вам делать только 60 запросов в минуту, а также ограничивает, к каким типам данных вы можете получить доступ, чего нам пока достаточно…

Чтобы запустить весь этот вид API, нам нужно будет Зарегистрироваться на их веб-странице и получить наш ключ API, в этом случае его довольно легко получить, после регистрации вы будете перенаправлены на панель управления, затем вы переходите к на вкладке Ключи API и там вы найдете свой ключ API, он должен быть примерно таким:

APIKey: `995507f17d707fccd35hd38301ef3a27`

Здорово! У нас уже есть ключ API, поэтому мы можем начать с ним работать.

В разделе документации вы найдете способ делать запросы к API и получать нужную информацию. Если мы хотим найти текущую погоду для определенного города, мы используем:

api.openweathermap.org/data/2.5/weather?q={city name}&appid={your api key}
api.openweathermap.org/data/2.5/weather?q={city name},{state code}&appid={your api key}
api.openweathermap.org/data/2.5/weather?q={city name},{state code},{country code}&appid={your api key}

И вы получите такой ответ в формате JSON:

{
  "coord": {
    "lon": -122.08,
    "lat": 37.39
  },
  "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "clear sky",
      "icon": "01d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 282.55,
    "feels_like": 281.86,
    "temp_min": 280.37,
    "temp_max": 284.26,
    "pressure": 1023,
    "humidity": 100
  },
  "visibility": 16093,
  "wind": {
    "speed": 1.5,
    "deg": 350
  },
  "clouds": {
    "all": 1
  },
  "dt": 1560350645,
  "sys": {
    "type": 1,
    "id": 5122,
    "message": 0.0139,
    "country": "US",
    "sunrise": 1560343627,
    "sunset": 1560396563
  },
  "timezone": -25200,
  "id": 420006353,
  "name": "Mountain View",
  "cod": 200
}

Обратите внимание, что температура указывается в градусах Кельвина. Если вы хотите получить температуру в градусах Цельсия или Фаренгейта, вам потребуется использовать следующие запросы:

Celsius: api.openweathermap.org/data/2.5/find?q=London&units=metric
Fahrenheit: api.openweathermap.org/data/2.5/find?q=London&units=imperial

Хорошо. У нас есть представление о том, как работает API, давайте перейдем к самой интересной части — кодированию нашего приложения.

Мы собираемся создать простой файл HTML с формой (с тегом поиска ввода и кнопкой) и разделом для отображения результатов нашего запроса. Для начала достаточно, не стесняйтесь добавлять все, что хотите, но здесь мы собираемся сохранить это простым на данный момент.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  <script src="https://kit.fontawesome.com/2c6133bcaa.js" crossorigin="anonymous"></script>
  <title>Weather APP</title>
</head>
<body>    
    <main id="main" class="position-relative p-5">
        <div class="text-center bg-dark p-3 w-75 mx-auto d-flex flex-column">
            <h1 class="text-white-50">Search by Location</h1>
            <h5 class="text-white-50">Write the location to get the weather</h5>
            <form id="searching" action="javascript:void(0);">
              <input class="form-class w-50" type="search" id="search" placeholder="Input your search keyword" name="search">
              <br><br>
              <input type="submit" class="btn btn-warning" id="submit" value="Weather" name="weather">
            </form>
        </div>
    </main>
    <section id="section" class="bg-dark p-4">
      <div class="card bg-dark text-white w-50 m-auto">
        <div id="image"></div>
        <div class="card-img-overlay">
          <h5 class="card-title text-center text-warning" id="title"></h5>
          <div class="d-flex flex-row justify-content-around">
            <ul class="list-group list-unstyled">
              <li class="list-group-item" id="temp"></li>
              <li class="list-group-item" id="feel"></li>
              <li class="list-group-item" id="desc"></li>
              <li class="list-group-item" id="pressure"></li>
              <li class="list-group-item" id="humidity"></li>
              <li class="list-group-item" id="sunrise"></li>
            </ul>
            <ul class="list-group list-unstyled">
              <li class="list-group-item" id="minTemp"></li>
              <li class="list-group-item" id="maxTemp"></li>
              <li class="list-group-item" id="wind"></li>
              <li class="list-group-item" id="windDir"></li>
              <li class="list-group-item" id="clouds"></li>
              <li class="list-group-item" id="sunset"></li>
            </ul>
          </div>
          <br>
          <div class="text-center">
            <div class="d-inline"><input type="submit" id="farCel" class="btn btn-warning" value="Celsius/Farenheit"></div>
        </div>
        </div>
      </div>
    </section>
    <section id="section2" class="bg-dark pt-3">
      <h3 id="cityName" class="text-center text-warning"></h3>
      <div class="row d-flex justify-content-around w-100" id="row"></div>
    </section>    
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
  <script src="main.js"></script>
</body>
</html>

В нашем JS-файле мы собираемся добавить прослушиватель событий на кнопку отправки, чтобы мы могли использовать ввод (в данном случае город), предоставленный пользователем.

const submit = document.getElementById('submit');
submit.addEventListener('click', getLocation.bind(this, 'search'));
function getLocation(searchBar) {    
const city=document.getElementById(searchBar).value).toLowerCase();    getSearch(city);  
}

А затем функция для получения данных из API. Поскольку мы работаем с API, нам нужно использовать промисы или асинхронные функции, это ваш выбор, используйте тот, который вам удобнее, я буду использовать асинхронную функцию, так как мне удобнее синтаксис и, на мой взгляд, улучшает читабельность кода. Я передаю данные JSON в функцию `showFlow`, где мы будем управлять отображением информации. Мы также добавляем оповещение в случае, если API не может найти город. Что-то вроде этого:

async function getSearch(city) {
    try {
      const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=995507f17d707fccd35hd38301ef3a27&units=metric`;
      const response = await fetch(url, { mode: 'cors' });
      const cityData = await response.json();
      showFlow(cityData);
    } catch (error) {
      console.error('Error:', error);
      alert('Could not find the location');
    }
  }

Идеально! На данный момент мы получили ввод пользователя и запросили информацию у API, и теперь мы можем использовать ответ JSON для отображения результатов на экране. Здесь нам понадобится немного манипуляций с DOM, чтобы добавить имеющуюся информацию так, как мы хотим. В этом случае я использовал немного Bootstrap для создания карточки и отображения там информации. Нравится:

function fillCard(data) {
    addInnerText('title', `${data.name}, ${data.sys.country}`);
    addInnerText('temp', `<i class="fas fa-thermometer-half text-warning my-2"></i> Temp: ${data.main.temp} Celsius`);
    addInnerText('feel', `<i class="fas fa-meteor text-warning my-2"></i> Feel: ${data.main.feels_like} Celsius`);
    addInnerText('desc', `<i class="fas fa-cloud-sun-rain text-warning my-2"></i> ${data.weather[0].main}`);
    addInnerText('pressure', `<i class="fas fa-compress-arrows-alt text-warning my-2"></i> Pressure: ${data.main.pressure} hPa`);
    addInnerText('humidity', `<i class="fas fa-percent text-warning my-2"></i> Humidity: ${data.main.humidity}%`);
    addInnerText('minTemp', `<i class="fas fa-temperature-low text-warning my-2"></i> Min: ${data.main.temp_min} Celsius`);
    addInnerText('maxTemp', `<i class="fas fa-temperature-high text-warning my-2"></i> Max: ${data.main.temp_max} Celsius`);
    addInnerText('wind', `<i class="fas fa-wind text-warning my-2"></i> ${data.wind.speed} meter/sec`);
    addInnerText('windDir', `<i class="fas fa-compass text-warning my-2"></i> ${data.wind.deg} degrees`);
    addInnerText('clouds', `<i class="fas fa-cloud text-warning my-2"></i> Clouds: ${data.clouds.all}%`);
    addInnerText('sunrise', `<i class="fas fa-sun text-warning my-2"></i> Sunrise: ${new Date((data.sys.sunrise + data.timezone) * 1000).toUTCString().slice(-11, -7)} AM`);
    addInnerText('sunset', `<i class="fas fa-sun text-warning my-2"></i> Sunset: ${new Date((data.sys.sunset + data.timezone) * 1000).toUTCString().slice(-11, -7)} PM`);
  }

Я создал вспомогательную функцию, чтобы не повторять код и содержать его в чистоте.

const addInnerText = function addInnerText(className, text) {
    const element = document.getElementById(className);
    element.innerHTML = text;
    return element.innerHTML;
  };

И добавил функцию смены фонового изображения в зависимости от фактической погоды города, используя коды предоставляемые API:

function imageSwitch(data, id) {
    const code = data.weather[0].id;
    switch (true) {
      case code >= 200 && code <= 232:
        document.getElementById(id).style.backgroundImage = "url('../src/images/lighting.jpg')";
        break;
      case code >= 300 && code <= 321:
        document.getElementById(id).style.backgroundImage = "url('../src/images/drizzle.jpg')";
        break;
      case code >= 500 && code <= 531:
        document.getElementById(id).style.backgroundImage = "url('../src/images/rain.jpg')";
        break;
      case code >= 600 && code <= 622:
        document.getElementById(id).style.backgroundImage = "url('../src/images/snow.jpg')";
        break;
      case code >= 701 && code <= 781:
        document.getElementById(id).style.backgroundImage = "url('../src/images/mist.jpg')";
        break;
      case code >= 801 && code <= 804:
        document.getElementById(id).style.backgroundImage = "url('../src/images/rainclouds.jpg')";
        break;
      case code === 800:
        document.getElementById(id).style.backgroundImage = "url('../src/images/shiningsun.jpg')";
        break;
      default:
        document.getElementById(id).style.backgroundImage = "url('../src/images/bluesky.jpg')";
        break;
    }
  }

Готово! У вас есть приложение погоды, в котором вы будете отображать текущую погоду в данном городе. У тебя нет оправданий, если ты промокнешь.

Отсюда вы можете добавить гораздо больше функций для сайта, таких как прогноз погоды, исторические данные о погоде, вы можете добавить функцию автозаполнения в строку поиска… Отныне вам решать, как должно выглядеть ваше приложение.

Вывод

Как видите, работать с API довольно легко и просто, но каждый API уникален, и вы должны потратить некоторое время на их документацию, чтобы понять, как они работают и какой ответ они предоставляют. Получив информацию, вы можете работать с ней так, как хотите, и отображать нужные данные.

Спасибо за чтение.

Вы можете проверить полный код в моем GitHub.