如何使用Openweathermap API在Node.js中创建一个天气应用程序

597 阅读9分钟

使用Openweathermap API在Node.js中创建一个天气应用程序

天气预报对于我们的日常生活是非常必要的。它可以帮助我们根据预期做好准备和制定计划。许多气象站被放置在世界各地,以获取实时的天气元素数据。

这些数据包括六个元素,如降水、风、大气压力、云量和温度。有了这些,你可以分析趋势,知道明天的数据预测或预测天气。

这些大块的数据大多是在基站使用强大而复杂的系统进行处理。然后他们通过API分享这些数据,(无论是长期分析的数据还是实时数据)。这样做的公司包括OpenWeatherMap和Dark Sky。

在本教程中,你将学习如何使用OpenWeatherMap API建立一个漂亮的天气应用程序。

主要收获

在本教程结束时,你将学会。

  • 什么是OpenWeatherMap API。
  • 如何使用OpenWeatherMap API。
  • 如何使用HTML、CSS和JavaScript建立一个漂亮的天气网站。
  • 如何将API集成到系统中。
  • 如何运行网络应用程序。

先决条件

跟随本教程所需的一些基础知识包括。

  • 网络开发过程中的一些基本知识。
  • Node.js的基础知识。
  • 在电脑上安装一个IDE/文本编辑器。
  • 一个良好和稳定的网络连接。

如果你具备以上所有条件,让我们进入一个工作项目的步骤。

获取API密钥

访问openweathermap.org/,并创建一个新的帐户,如果你已经有一个帐户,请登录。

OpenWeatherMap。提供免费和付费服务。这完全取决于所要求的数据的类型和大小。此外,它也取决于每次请求的数量。

openweathermap login

点击你在导航栏右上方的账户名称链接。在下拉菜单中,选择 "我的API密钥"。你可以用新的名字生成一个,或使用所提供的默认的一个。

为安全起见,请确保它不被任何人看到。另外,不要在你的应用程序中直接保存它。

如果出现任何无效的 "无效的API密钥"错误,你可以创建一个新的密钥并保存起来使用。一个以前从未使用过的。

设置项目

创建一个新的目录,这将是你的根目录,并将其命名为Weather ,在其中,你将通过使用下面的命令初始化Node.js项目。

npm init -y

该命令接受终端对话中的所有默认选项。它在根目录下创建一个新的配置文件,名为package.json

接下来,创建一个名为views 的文件夹,并在其中创建一个名为index.ejs 的文件。这个文件将允许我们使用ejs 视图引擎查看结果。

在根目录下创建另一个名为public 的文件夹,并在其中创建一个名为css 的文件夹。在根目录下创建分别名为.envserver.js 的文件。项目的结构将如下图所示。

文件夹结构

.Weather
├── node_modules (Folder)
├── public (Folder)
│   ├── css (Folder)
│       └── style.css (File)
├── views (Folder)
│   └── index.ejs (File)
├── .env (File)
├── package.json (File)
└── server.js (File)

现在你将修改你的文件,如下。

安装依赖项

以下是你在项目中需要的依赖项。

  • Express:这将帮助我们创建服务器并提供你的API。
  • dotenv:这将帮助我们访问.env 文件中的隐藏键。
  • body-parser:这是一个Node.js主体解析中间件。它将允许我们在你的处理程序之前在中间件中解析传入的请求体。这些都是在req.body 属性下可用的。
  • request:这将有助于进行http调用。
  • ejs:这将有助于将你的模板转换为可在浏览器中查看的HTML静态页面。

你将通过在终端运行以下命令来安装它们。

npm i express dotenv body-parser request ejs

检查应用程序的配置

让我们调整一下package.json 文件中的应用程序配置。

打开该文件并在其中添加一个启动脚本,如下所示。

...
        "scripts": {
            "start": "node server.js",
            "test": "echo \"Error: no test specified\" && exit 1"
        },
...

你的完整的package.json ,看起来应该是这样的。

{
  "name": "Weather",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.17.2",
    "dotenv": "^10.0.0",
    "express": "^4.15.3",
    "request": "^2.81.0"
  }
}

应用程序入口点

前往server.js 文件,这是你的应用程序的主要入口点。

你将需要在你的代码中做以下工作。

  • 导入应用程序的依赖性

这些是你在你的应用程序中安装的依赖项。为了使用它们,你可以使用require 关键字来导入它们,如下图所示。

// Require application dependencies
// These are express, body-parser, and request

const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");
const app = express();

// Configure dotenv package

require("dotenv").config();
  • 设置你的API KEY、Express应用程序和body-parser配置,以及你的JavaScript模板视图引擎。
// Set up your OpenWeatherMap API_KEY

const apiKey = `${process.env.API_KEY}`;

// Setup your express app and body-parser configurations
// Setup your javascript template view engine
// we will serve your static pages from the public directory, it will act as your root directory
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
  • 接下来,你将设置启动时的默认显示。这基本上是用户在向/ 路径运行获取请求时将看到的页面。
// Setup your default display on launch
app.get("/", function (req, res) {
  // It will not fetch and display any data in the index page
  res.render("index", { weather: null, error: null });
});
  • 接下来,设置post request的显示。这是当你用你想要的数据向API发出帖子请求时显示的页面。你的获取将在页面加载时发生在/ 端点上。

在这里,你将使用帖子请求中传递的城市和你的.env 文件中的API_KEY来从API获取数据。

// On a post request, the app shall data from OpenWeatherMap using the given arguments
app.post('/', function(req, res) {

    // Get city name passed in the form
    let city = req.body.city;

    // Use that city name to fetch data
    // Use the API_KEY in the '.env' file
    let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`;
  • 接下来,我们将使用URL中传递的凭证从OpenWeatherMap API请求数据。在正文部分找到的数据将被存储在本地变量中,然后在网页上呈现。

如果出现错误,它将显示一个错误信息,如下图所示。

    // Request for data using the URL
    request(url, function(err, response, body) {

        // On return, check the json data fetched
        if (err) {
            res.render('index', { weather: null, error: 'Error, please try again' });
        } else {
            let weather = JSON.parse(body);
  • 接下来,你将检查你的天气数据是否返回未定义。这将表明有错误。如果不是,你将继续存储内容。
            // you shall output it in the console just to make sure that the data being displayed is what you want
            console.log(weather);

            if (weather.main == undefined) {
                res.render('index', { weather: null, error: 'Error, please try again' });
            } else {
                // we shall use the data got to set up your output
                let place = `${weather.name}, ${weather.sys.country}`,
                  /* you shall calculate the current timezone using the data fetched*/
                  weatherTimezone = `${new Date(
                    weather.dt * 1000 - weather.timezone * 1000
                  )}`;
                let weatherTemp = `${weather.main.temp}`,
                  weatherPressure = `${weather.main.pressure}`,
                  /* you will fetch the weather icon and its size using the icon data*/
                  weatherIcon = `http://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`,
                  weatherDescription = `${weather.weather[0].description}`,
                  humidity = `${weather.main.humidity}`,
                  clouds = `${weather.clouds.all}`,
                  visibility = `${weather.visibility}`,
                  main = `${weather.weather[0].main}`,
                  weatherFahrenheit;
                weatherFahrenheit = (weatherTemp * 9) / 5 + 32;

                // you shall also round off the value of the degrees fahrenheit calculated into two decimal places
                function roundToTwo(num) {
                  return +(Math.round(num + "e+2") + "e-2");
                }
                weatherFahrenheit = roundToTwo(weatherFahrenheit);
  • 接下来,存储的值现在将被渲染到网页上,生成一个静态网页,显示给用户。
                // you shall now render the data to your page (index.ejs) before displaying it out
                res.render("index", {
                  weather: weather,
                  place: place,
                  temp: weatherTemp,
                  pressure: weatherPressure,
                  icon: weatherIcon,
                  description: weatherDescription,
                  timezone: weatherTimezone,
                  humidity: humidity,
                  fahrenheit: weatherFahrenheit,
                  clouds: clouds,
                  visibility: visibility,
                  main: main,
                  error: null,
                });
              }
            }
        }
    });
});

注意:你可以根据需要获取和显示尽可能多的数据。这是在收到的JSON中。

  • 设置你的服务器端口配置并启动服务器。

这里你将设置你的服务器监听端口。你还将启动服务器,并添加一个运行时显示的信息。你将为你的项目利用端口5000 ,可以在http://localhost:5000

// you will set up your port configurations. You will also start the server and add a message to display when running.
app.listen(5000, function () {
  console.log("Weather app listening on port 5000!");
});

你可以直接复制代码并将其粘贴到你的文件中。

设置你的视图

现在让我们在应用程序中设置你的动态网页。记住,你正在使用EJS作为你的模板引擎。在views 文件夹中找到的index.ejs 文件中,你将创建一个网页模板,在显示过程中,一旦取到值,将被转换为静态网页。

注意:当这个渲染静态网页时,它们将从public 文件夹中被提供,它将作为根目录。这是因为在server.js 文件中的这行代码,app.use(express.static('public')); 。因此,它将从'public'文件夹中获得其资产。这将包括'css'甚至是图像文件。

这就是你将在index.ejs 文件中做的事情。

  • 在你的index.ejs 中创建一个新的bootstrap boilerplate。链接将在'css'文件夹内找到的css 文件。在其中,你还将把网站的标题改为Weather ,并从一个URL中添加一个favicon,如下面的代码所示。
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Weather</title>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />

    <!-- Bootstrap CSS -->
    <!-- Use some bootstrap CSS and google fonts to quicken the process -->
    <!-- you shall also add a favicon -->
    <link
      rel="shortcut icon"
      href="https://img.icons8.com/office/16/000000/sunset--v2.png"
      type="image/x-icon"
    />
    <link rel="stylesheet" type="text/css" href="/css/style.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Open+Sans:300"
      rel="stylesheet"
      type="text/css"
    />
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
      integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
      crossorigin="anonymous"
    />
  </head>

  <body>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script
      src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
      integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
      integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
      integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
      crossorigin="anonymous"
    ></script>
  </body>
</html>
  • 在body标签内,就在bootstrap脚本的上方,你将添加你的内容。你还应使用数据属性来访问从API渲染到它的数据。如果没有数据,它将显示错误。
<!-- Main container -->
<div class="container">

  <!-- This shall hold the input fields and the output data -->
  <fieldset>
    <!-- This form shall be used to fetch your city name -->
    <form action="/" method="post">
      <input name="city" type="text" class="ghost-input" placeholder="Enter a City" required>
      <input type="submit" class="ghost-button" value="Get Weather">
    </form>

    <!-- Upon fetching of data you will display it -->
    <%if( weather !== null){ %>
    <div class="grid">
      <p>
        <%= place %>
      </p>
      <p class="text-muted small">
        <%= timezone %>
      </p>
    </div>

    <!-- You can find other data fetched by the app on the console in JSON form and display it as you please -->
    <div class="card-deck">
      <div class="card card-accent-dark mb-3" style="max-width: 18rem;">
        <div class="card-header">Summary</div>
        <div class="card-body text-dark">Bootstrap CSS
          <img src="<%= icon %>" alt="Weather-Icon">
          <h5 class="card-title">Temperature</h5>
          <p class="card-text">
            In Degrees:
            <%= temp %>°C/
            <%= fahrenheit %>°F
          </p>
          <h5 class="card-title">Main</h5>
          <p class="card-text">
            <%= main %>
          </p>
        </div>
      </div>
      <div class="card-deck">
        <div class="card card-acTomorrowcent-dark mb-3" style="max-width: 18rem;">
          <div class="card-header">Description</div>
          <div class="card-body text-dark">
            <h5 class="card-title">Overall Description: </h5>
            <p class="card-text">
              <%= description %>
            </p>
            <h5 class="card-title">Cloud coverage: </h5>
            <p class="card-text">
              <%= clouds %>%
            </p>
            <h5 class="card-title">Visibility: </h5>
            <p class="card-text">
              <%= visibility %> meters
            </p>
          </div>
        </div>
        <div class="card-deck">
          <div class="card card-accent-dark mb-3" style="max-width: 18rem;">
            <div class="card-header">Other info</div>
            <div class="card-body text-dark">
              <h5 class="card-title">Humidity: </h5>
              <p class="card-text">
                <%= humidity %> g.m-3
              </p>
            </div>
            <div class="card-body text-dark">
              <h5 class="card-title">Pressure: </h5>
              <p class="card-text">
                <%= pressure %> N·m−2
              </p>
            </div>
          </div>
        </div>

        <% } %>

        <% if(error !== null){ %>
        <p>
          <%= error %>
        </p>
        <% } %>
  </fieldset>
</div>

注意:脚本总是放在你的页面上的主要内容之后。这将允许页面内容在执行JavaScript文件之前完全加载,从而防止错误。这是很好的编码实践。

塑造你的页面

在代码执行过程中,你应使用你的'style.css'文件对生成并存储在公共文件夹中的静态网页进行造型。

这将是你的CSS格式。

body {
  width: auto;
  margin: 0 auto;
  font-family: "Open Sans", sans-serif;
}

/* This will format the whole fieldset content*/

.container {
  width: 80%;
  margin: 0 auto;
}

/* This will format the whole fieldset content*/

fieldset {
  display: block;
  -webkit-margin-start: 0px;
  -webkit-margin-end: 0px;
  -webkit-padding-before: 0em;
  -webkit-padding-start: 0em;
  -webkit-padding-end: 0em;
  -webkit-padding-after: 0em;
  border: 0px;
  border-image-source: initial;
  border-image-slice: initial;
  border-image-width: initial;
  border-image-outset: initial;
  border-image-repeat: initial;
  min-width: -webkit-min-content;
  padding: 30px;
}

/* Format the input section */

/* Format the input, paragraph, hover effect, focus and button */
.ghost-input,
p {
  display: block;
  font-weight: 300;
  width: 100%;
  font-size: 25px;
  border: 0px;
  outline: none;
  width: 100%;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  color: #4b545f;
  background: #fff;
  font-family: Open Sans, Verdana;
  padding: 10px 15px;
  margin: 30px 0px;
  -webkit-transition: all 0.1s ease-in-out;
  -moz-transition: all 0.1s ease-in-out;
  -ms-transition: all 0.1s ease-in-out;
  -o-transition: all 0.1s ease-in-out;
  transition: all 0.1s ease-in-out;
}

.ghost-input:focus {
  border-bottom: 1px solid #ddd;
}

.ghost-button {
  background-color: transparent;
  border: 2px solid #ddd;
  padding: 10px 30px;
  width: 100%;
  min-width: 350px;
  -webkit-transition: all 0.1s ease-in-out;
  -moz-transition: all 0.1s ease-in-out;
  -ms-transition: all 0.1s ease-in-out;
  -o-transition: all 0.1s ease-in-out;
  transition: all 0.1s ease-in-out;
}

.ghost-button:hover {
  border: 2px solid #515151;
}

p {
  color: #e64a19;
}

应用环境变量

你现在将输入你的应用环境常量。在你的.env 文件内,你将放置你的OpenWeatherMap API KEY。

只需在文件中添加以下内容,然后在其后面复制粘贴获得的密钥。

API_KEY=

保存该文件。

运行和访问该应用程序

要运行该应用程序,你将利用先前在'package.json'文件中添加的'start'脚本。

这可以通过在内置终端中运行以下代码来完成。

npm run start

你也可以用以下方式启动该应用程序。

node server.js

在浏览器中访问该应用程序:localhost:5000 。输入您选择的城市名称,并点击 "获取天气 "按钮。

它将获取天气数据并在网络浏览器和控制台中返回结果。

你可以在终端上使用Ctrl + C 关闭该应用程序。

额外的项目API

一些显示在下面。

OpenWeatherMap Other Urls

你可以尝试获取数据并在控制台或浏览器中显示它。

  • 尝试获取并使用地理定位,根据用户的位置来获取用户的天气数据。
  • 尝试在你的网站上添加一个在这个链接中找到的天气图:https://openweathermap.org/api

结论

你可以从OpenWeatherMap网站上获取更多的数据。这对于根据需要定制你的应用程序数据是很有用的。这也包括可以嵌入到网页中的实时天气图。在天气预报中,数据越多越好。