Eric Whale

Add Get current Weather API

1 // Weather broadcasting page 1 // Weather broadcasting page
2 -import axios from "axios";
3 import { useState, useEffect } from "react"; 2 import { useState, useEffect } from "react";
3 +import { Navigate } from "react-router-dom";
4 +import weatherService from "./service/weather";
4 // components 5 // components
5 import Bottombar from "./components/Bottombar"; 6 import Bottombar from "./components/Bottombar";
6 import Topbar from "./components/Topbar"; 7 import Topbar from "./components/Topbar";
7 -import ChatroomBox from "./components/ChatroomBox";
8 8
9 function App() { 9 function App() {
10 + const token = sessionStorage.getItem("user-token");
11 + const [weather, setWeather] = useState();
12 + const [forecast, setForecast] = useState();
13 + const [air, setAir] = useState();
14 +
15 + const handleData = async (e) => {
16 + setWeather(null);
17 + setForecast(null);
18 + setAir(null);
19 + if (e.target.id === "weather") {
20 + const weatherData = await weatherService.getWeather(token);
21 + setWeather(weatherData);
22 + } else if (e.target.id === "forecast") {
23 + const forecasetData = await weatherService.getForecaset(token);
24 + setForecast(forecasetData);
25 + } else if (e.target.id === "air") {
26 + const airData = await weatherService.getAirPollution(token);
27 + setAir(airData);
28 + }
29 + };
30 +
31 + if (!token) {
32 + return <Navigate to="/login" />;
33 + }
34 +
10 return ( 35 return (
11 <div> 36 <div>
12 <Topbar /> 37 <Topbar />
13 <h1>Weather Page (home)</h1> 38 <h1>Weather Page (home)</h1>
14 - <div></div> 39 + <div className="weather-buttons">
40 + <button id="weather" onClick={(e) => handleData(e)}>
41 + Weather
42 + </button>
43 + <button id="forecast" onClick={(e) => handleData(e)}>
44 + Forecast
45 + </button>
46 + <button id="air" onClick={(e) => handleData(e)}>
47 + Air Pollution
48 + </button>
49 + </div>
50 +
51 + {!weather ? (
52 + ""
53 + ) : (
54 + <div>
55 + <h2>
56 + {weather.meta.city} ({weather.meta.country}) - {weather.description}
57 + </h2>
58 + <small>Time Zone : UTC {weather.meta.timezone}</small>
59 + <p>
60 + Temperature : {weather.temp.realCelcius} C / feels like{" "}
61 + {weather.temp.feelCelcius} C
62 + </p>
63 + <p>Wind : {weather.types.wind} m/s</p>
64 + <p>Cloud : {weather.types.clouds} %</p>
65 + <p>{weather.rain ? "rain : Yes" : "rain : No"}</p>
66 + <p>{weather.snow ? "snow : Yes" : "snow : No"}</p>
67 + </div>
68 + )}
15 69
16 <Bottombar /> 70 <Bottombar />
17 </div> 71 </div>
...@@ -19,11 +73,3 @@ function App() { ...@@ -19,11 +73,3 @@ function App() {
19 } 73 }
20 74
21 export default App; 75 export default App;
22 -
23 -// {Array.isArray(chats) ? (
24 -// chats.map((chat, i) => {
25 -// return <ChatroomBox key={i} chat={chat} />;
26 -// })
27 -// ) : (
28 -// <h2>No chatting room!</h2>
29 -// )}
......
1 import { Link } from "react-router-dom"; 1 import { Link } from "react-router-dom";
2 // styles 2 // styles
3 import "../styles/bar.scss"; 3 import "../styles/bar.scss";
4 -import { TiWeatherPartlySunny } from "react-icons/ti"; 4 +import { FcHome } from "react-icons/fc";
5 import { AiFillSetting } from "react-icons/ai"; 5 import { AiFillSetting } from "react-icons/ai";
6 6
7 function Topbar() { 7 function Topbar() {
8 return ( 8 return (
9 <div className="topbar"> 9 <div className="topbar">
10 <Link to="/" className="logo"> 10 <Link to="/" className="logo">
11 - <TiWeatherPartlySunny /> 11 + <FcHome />
12 </Link> 12 </Link>
13 <Link to="/settings" className="settings"> 13 <Link to="/settings" className="settings">
14 <AiFillSetting /> 14 <AiFillSetting />
......
...@@ -8,7 +8,7 @@ import Signup from "./routes/signup"; ...@@ -8,7 +8,7 @@ import Signup from "./routes/signup";
8 import Login from "./routes/login"; 8 import Login from "./routes/login";
9 import Users from "./routes/users"; 9 import Users from "./routes/users";
10 import Settings from "./routes/settings"; 10 import Settings from "./routes/settings";
11 -import Tell from "./routes/tell"; 11 +import Tweet from "./routes/tweet";
12 import NotFound from "./routes/notfound"; 12 import NotFound from "./routes/notfound";
13 // styles 13 // styles
14 import "./styles/layout.scss"; 14 import "./styles/layout.scss";
...@@ -24,7 +24,7 @@ root.render( ...@@ -24,7 +24,7 @@ root.render(
24 <Route exact path="/signup" element={<Signup />} /> 24 <Route exact path="/signup" element={<Signup />} />
25 <Route exact path="/users" element={<Users />} /> 25 <Route exact path="/users" element={<Users />} />
26 <Route exact path="/settings" element={<Settings />} /> 26 <Route exact path="/settings" element={<Settings />} />
27 - <Route exact path="/tell" element={<Tell />} /> 27 + <Route exact path="/tell" element={<Tweet />} />
28 <Route path="*" element={<NotFound />} /> 28 <Route path="*" element={<NotFound />} />
29 </Routes> 29 </Routes>
30 </BrowserRouter> 30 </BrowserRouter>
......
...@@ -15,7 +15,7 @@ function Login() { ...@@ -15,7 +15,7 @@ function Login() {
15 }); 15 });
16 16
17 useEffect(() => { 17 useEffect(() => {
18 - if (localStorage.key("user-token")) { 18 + if (sessionStorage.key("user-token")) {
19 navigate("/", { replace: true }); 19 navigate("/", { replace: true });
20 } 20 }
21 }, [loginSuccess, setLoginSuccess, navigate]); 21 }, [loginSuccess, setLoginSuccess, navigate]);
...@@ -29,6 +29,10 @@ function Login() { ...@@ -29,6 +29,10 @@ function Login() {
29 29
30 const handleSubmit = async (e) => { 30 const handleSubmit = async (e) => {
31 e.preventDefault(); 31 e.preventDefault();
32 + if (!userinfo.email || !userinfo.password) {
33 + alert("Please fill all boxes");
34 + return;
35 + }
32 const answer = await authService.handleLogin(userinfo); 36 const answer = await authService.handleLogin(userinfo);
33 setLoginSuccess(answer); 37 setLoginSuccess(answer);
34 }; 38 };
......
...@@ -11,12 +11,13 @@ function Signup() { ...@@ -11,12 +11,13 @@ function Signup() {
11 const [userinfo, setUserInfo] = useState({ 11 const [userinfo, setUserInfo] = useState({
12 username: "", 12 username: "",
13 country: "", 13 country: "",
14 + city: "",
14 email: "", 15 email: "",
15 password: "", 16 password: "",
16 }); 17 });
17 18
18 useEffect(() => { 19 useEffect(() => {
19 - if (localStorage.key("user-token")) { 20 + if (sessionStorage.key("user-token")) {
20 navigate("/", { replace: true }); 21 navigate("/", { replace: true });
21 } 22 }
22 }, [signupSuccess, setSignupSuccess, navigate]); 23 }, [signupSuccess, setSignupSuccess, navigate]);
...@@ -44,6 +45,11 @@ function Signup() { ...@@ -44,6 +45,11 @@ function Signup() {
44 45
45 <br /> 46 <br />
46 47
48 + <p>
49 + <b>Country Code</b> and <b>City Name</b> is required for Weather
50 + service!
51 + </p>
52 +
47 <form className="authForm" onSubmit={(e) => handleSubmit(e)}> 53 <form className="authForm" onSubmit={(e) => handleSubmit(e)}>
48 <label htmlFor="username"> 54 <label htmlFor="username">
49 <input 55 <input
...@@ -63,6 +69,15 @@ function Signup() { ...@@ -63,6 +69,15 @@ function Signup() {
63 id="country" 69 id="country"
64 /> 70 />
65 </label> 71 </label>
72 + <label htmlFor="city">
73 + <input
74 + placeholder="City Name"
75 + onChange={(e) => onChange(e)}
76 + value={userinfo.city}
77 + type="text"
78 + id="city"
79 + />
80 + </label>
66 <label htmlFor="email"> 81 <label htmlFor="email">
67 <input 82 <input
68 placeholder="email" 83 placeholder="email"
......
1 -function Tell() {
2 - return <div>tell</div>;
3 -}
4 -
5 -export default Tell;
1 +function Tweet() {
2 + return <div>Tweet</div>;
3 +}
4 +
5 +export default Tweet;
1 const axios = require("axios").default; 1 const axios = require("axios").default;
2 2
3 -const handleSignup = async ({ username, country, email, password }) => { 3 +const handleSignup = async ({ username, country, city, email, password }) => {
4 try { 4 try {
5 const response = await axios.post("http://localhost:8080/api/users", { 5 const response = await axios.post("http://localhost:8080/api/users", {
6 username, 6 username,
7 country, 7 country,
8 + city,
8 email, 9 email,
9 password, 10 password,
10 }); 11 });
11 if (response.data) { 12 if (response.data) {
12 - console.log("signup request sent..."); 13 + sessionStorage.setItem("user-token", JSON.stringify(response.data));
13 - localStorage.setItem("user-token", JSON.stringify(response.data));
14 return "success"; 14 return "success";
15 } 15 }
16 } catch (err) { 16 } catch (err) {
...@@ -25,8 +25,7 @@ const handleLogin = async ({ email, password }) => { ...@@ -25,8 +25,7 @@ const handleLogin = async ({ email, password }) => {
25 password, 25 password,
26 }); 26 });
27 if (response.data) { 27 if (response.data) {
28 - console.log("signin request sent..."); 28 + sessionStorage.setItem("user-token", JSON.stringify(response.data));
29 - localStorage.setItem("user-token", JSON.stringify(response.data));
30 return "success"; 29 return "success";
31 } 30 }
32 } catch (err) { 31 } catch (err) {
......
1 +const axios = require("axios").default;
2 +
3 +const getWeather = async (user) => {
4 + if (!user) {
5 + return;
6 + }
7 + try {
8 + const response = await axios.post("http://localhost:8080/api/weather");
9 + const data = response.data;
10 + const formattedData = {
11 + meta: {
12 + country: data.sys.country,
13 + city: data.name,
14 + timezone: data.timezone / 60 / 60,
15 + sunrise: data.sys.sunrise,
16 + sunset: data.sys.sunset,
17 + },
18 + description: data.weather[0].description,
19 + temp: {
20 + realCelcius: (data.main.temp - 273.15).toFixed(2),
21 + feelCelcius: (data.main.feels_like - 273.15).toFixed(2),
22 + realFer: ((data.main.temp - 273.15) * 9) / 5 + 32,
23 + feelFer: ((data.main.feels_like - 273.15) * 9) / 5 + 32,
24 + },
25 + types: {
26 + wind: data.wind.speed,
27 + clouds: data.clouds.all,
28 + rain: data.rain ? data.rain : null,
29 + snow: data.snow ? data.snow : null,
30 + },
31 + };
32 + return formattedData;
33 + } catch (err) {
34 + console.log(err);
35 + }
36 +};
37 +
38 +const getForecaset = async () => {
39 + return;
40 +};
41 +
42 +const getAirPollution = async () => {
43 + return;
44 +};
45 +
46 +const weatherService = {
47 + getWeather,
48 + getForecaset,
49 + getAirPollution,
50 +};
51 +
52 +export default weatherService;
...@@ -17,4 +17,18 @@ ...@@ -17,4 +17,18 @@
17 input { 17 input {
18 width: 100%; 18 width: 100%;
19 } 19 }
20 +
21 + label {
22 + margin-top: 0.2rem;
23 + margin-bottom: 0.2rem;
24 + }
25 +}
26 +
27 +.weather-buttons {
28 + display: flex;
29 + flex-direction: row;
30 + button {
31 + margin-left: 0.2rem;
32 + margin-right: 0.2rem;
33 + }
20 } 34 }
......
...@@ -8,10 +8,10 @@ const { jwtGenerator } = require("../config/jwt"); ...@@ -8,10 +8,10 @@ const { jwtGenerator } = require("../config/jwt");
8 // @route POST /api/users 8 // @route POST /api/users
9 // @access Public 9 // @access Public
10 const signupUser = asyncHandler(async (req, res) => { 10 const signupUser = asyncHandler(async (req, res) => {
11 - const { username, country, email, password } = req.body; 11 + const { username, country, city, email, password } = req.body;
12 - if (!username || !email || !password) { 12 + if (!username || !country || !city || !email || !password) {
13 res.status(400); 13 res.status(400);
14 - throw new Error("Please fill in required fields"); 14 + throw new Error("Please fill in all fields");
15 } 15 }
16 16
17 // Check if user already exists 17 // Check if user already exists
...@@ -29,6 +29,7 @@ const signupUser = asyncHandler(async (req, res) => { ...@@ -29,6 +29,7 @@ const signupUser = asyncHandler(async (req, res) => {
29 const user = await User.create({ 29 const user = await User.create({
30 username, 30 username,
31 country, 31 country,
32 + city,
32 email, 33 email,
33 password: hashedPassword, 34 password: hashedPassword,
34 }); 35 });
...@@ -40,6 +41,7 @@ const signupUser = asyncHandler(async (req, res) => { ...@@ -40,6 +41,7 @@ const signupUser = asyncHandler(async (req, res) => {
40 _id: user.id, 41 _id: user.id,
41 username: user.username, 42 username: user.username,
42 country: user.country, 43 country: user.country,
44 + city: user.city,
43 email: user.email, 45 email: user.email,
44 token: jwtGenerator(user._id), 46 token: jwtGenerator(user._id),
45 }); 47 });
......
1 +const bcrypt = require("bcryptjs");
2 +const axios = require("axios").default;
3 +const User = require("../models/userModel");
4 +// handles "exception" inside of async express routes
5 +const asyncHandler = require("express-async-handler");
6 +
7 +// @desc Get current weather (API - Current Weather)
8 +// @route Get /api/weather
9 +// @access Public
10 +const getWeather = asyncHandler(async (req, res) => {
11 + const countryCode = "US";
12 + const cityName = "los angeles";
13 + const limit = 5;
14 +
15 + const metaGeoData = await axios.get(
16 + `http://api.openweathermap.org/geo/1.0/direct?q=${cityName},${countryCode}&limit=${limit}&appid=${process.env.OPENWEATHER_API_KEY}`
17 + );
18 + const data = metaGeoData.data[0];
19 + const geoData = {
20 + lat: data.lat,
21 + lon: data.lon,
22 + country: data.country,
23 + state: data.state,
24 + };
25 +
26 + const metaData = await axios.get(
27 + `https://api.openweathermap.org/data/2.5/weather?lat=${geoData.lat}&lon=${geoData.lon}&appid=${process.env.OPENWEATHER_API_KEY}`
28 + );
29 + const weatherData = metaData.data;
30 +
31 + res.json(weatherData);
32 +});
33 +
34 +// @desc Get weather forecast (3-hour Forecast 5 days)
35 +// @route GET /api/weather/forecast
36 +// @access Public
37 +const getForecast = asyncHandler(async (req, res) => {
38 + const lat = 35;
39 + const lon = 139;
40 + const data = await axios.get(
41 + `https://pro.openweathermap.org/data/2.5/forecast/hourly?lat=${lat}&lon=${lon}&appid=${process.env.OPENWEATHER_API_KEY2}`
42 + );
43 + console.log(data);
44 +});
45 +
46 +// @desc Get air pollution (Air Pollution API)
47 +// @route GET /api/weather/airpollution
48 +// @access Public
49 +const getAirPollution = asyncHandler(async (req, res) => {
50 + res.json({});
51 +});
52 +
53 +module.exports = {
54 + getWeather,
55 + getForecast,
56 + getAirPollution,
57 +};
58 +
59 +// use geocoding
1 -const mongoose = require("mongoose");
2 -
3 -const chatSchema = mongoose.Schema({
4 - room: {
5 - type: mongoose.Schema.Types.ObjectId,
6 - require: true,
7 - ref: "Chatroom",
8 - },
9 - conversation: [
10 - {
11 - message: {
12 - type: String,
13 - required: true,
14 - },
15 - },
16 - ],
17 -});
18 -
19 -module.exports = mongoose.model("Chat", chatSchema);
1 -const mongoose = require("mongoose");
2 -
3 -const chatroomSchema = mongoose.Schema(
4 - {
5 - roomName: {
6 - type: String,
7 - required: [true, "Please add chatroom name"],
8 - },
9 - participants: [
10 - {
11 - user: {
12 - type: mongoose.Schema.Types.ObjectId,
13 - required: true,
14 - ref: "User",
15 - },
16 - },
17 - ],
18 - },
19 - {
20 - timestamps: true,
21 - }
22 -);
23 -
24 -module.exports = mongoose.model("Chatroom", chatroomSchema);
...@@ -8,7 +8,11 @@ const userSchema = mongoose.Schema( ...@@ -8,7 +8,11 @@ const userSchema = mongoose.Schema(
8 }, 8 },
9 country: { 9 country: {
10 type: String, 10 type: String,
11 - required: false, 11 + required: true,
12 + },
13 + city: {
14 + type: String,
15 + required: true,
12 }, 16 },
13 email: { 17 email: {
14 type: String, 18 type: String,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
9 "version": "1.0.0", 9 "version": "1.0.0",
10 "license": "MIT", 10 "license": "MIT",
11 "dependencies": { 11 "dependencies": {
12 + "axios": "^0.27.2",
12 "bcryptjs": "^2.4.3", 13 "bcryptjs": "^2.4.3",
13 "colors": "^1.4.0", 14 "colors": "^1.4.0",
14 "cors": "^2.8.5", 15 "cors": "^2.8.5",
...@@ -148,6 +149,20 @@ ...@@ -148,6 +149,20 @@
148 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 149 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
149 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 150 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
150 }, 151 },
152 + "node_modules/asynckit": {
153 + "version": "0.4.0",
154 + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
155 + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
156 + },
157 + "node_modules/axios": {
158 + "version": "0.27.2",
159 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
160 + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
161 + "dependencies": {
162 + "follow-redirects": "^1.14.9",
163 + "form-data": "^4.0.0"
164 + }
165 + },
151 "node_modules/balanced-match": { 166 "node_modules/balanced-match": {
152 "version": "1.0.2", 167 "version": "1.0.2",
153 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 168 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
...@@ -503,6 +518,17 @@ ...@@ -503,6 +518,17 @@
503 "node": ">=0.1.90" 518 "node": ">=0.1.90"
504 } 519 }
505 }, 520 },
521 + "node_modules/combined-stream": {
522 + "version": "1.0.8",
523 + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
524 + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
525 + "dependencies": {
526 + "delayed-stream": "~1.0.0"
527 + },
528 + "engines": {
529 + "node": ">= 0.8"
530 + }
531 + },
506 "node_modules/component-emitter": { 532 "node_modules/component-emitter": {
507 "version": "1.3.0", 533 "version": "1.3.0",
508 "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 534 "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
...@@ -679,6 +705,14 @@ ...@@ -679,6 +705,14 @@
679 "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", 705 "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
680 "dev": true 706 "dev": true
681 }, 707 },
708 + "node_modules/delayed-stream": {
709 + "version": "1.0.0",
710 + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
711 + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
712 + "engines": {
713 + "node": ">=0.4.0"
714 + }
715 + },
682 "node_modules/denque": { 716 "node_modules/denque": {
683 "version": "2.0.1", 717 "version": "2.0.1",
684 "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", 718 "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
...@@ -929,6 +963,38 @@ ...@@ -929,6 +963,38 @@
929 "node": ">= 0.8" 963 "node": ">= 0.8"
930 } 964 }
931 }, 965 },
966 + "node_modules/follow-redirects": {
967 + "version": "1.15.1",
968 + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
969 + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
970 + "funding": [
971 + {
972 + "type": "individual",
973 + "url": "https://github.com/sponsors/RubenVerborgh"
974 + }
975 + ],
976 + "engines": {
977 + "node": ">=4.0"
978 + },
979 + "peerDependenciesMeta": {
980 + "debug": {
981 + "optional": true
982 + }
983 + }
984 + },
985 + "node_modules/form-data": {
986 + "version": "4.0.0",
987 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
988 + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
989 + "dependencies": {
990 + "asynckit": "^0.4.0",
991 + "combined-stream": "^1.0.8",
992 + "mime-types": "^2.1.12"
993 + },
994 + "engines": {
995 + "node": ">= 6"
996 + }
997 + },
932 "node_modules/forwarded": { 998 "node_modules/forwarded": {
933 "version": "0.2.0", 999 "version": "0.2.0",
934 "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1000 "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
...@@ -2769,6 +2835,20 @@ ...@@ -2769,6 +2835,20 @@
2769 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 2835 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
2770 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 2836 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
2771 }, 2837 },
2838 + "asynckit": {
2839 + "version": "0.4.0",
2840 + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
2841 + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
2842 + },
2843 + "axios": {
2844 + "version": "0.27.2",
2845 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
2846 + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
2847 + "requires": {
2848 + "follow-redirects": "^1.14.9",
2849 + "form-data": "^4.0.0"
2850 + }
2851 + },
2772 "balanced-match": { 2852 "balanced-match": {
2773 "version": "1.0.2", 2853 "version": "1.0.2",
2774 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 2854 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
...@@ -3019,6 +3099,14 @@ ...@@ -3019,6 +3099,14 @@
3019 "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 3099 "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
3020 "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" 3100 "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
3021 }, 3101 },
3102 + "combined-stream": {
3103 + "version": "1.0.8",
3104 + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
3105 + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
3106 + "requires": {
3107 + "delayed-stream": "~1.0.0"
3108 + }
3109 + },
3022 "component-emitter": { 3110 "component-emitter": {
3023 "version": "1.3.0", 3111 "version": "1.3.0",
3024 "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 3112 "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
...@@ -3151,6 +3239,11 @@ ...@@ -3151,6 +3239,11 @@
3151 "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", 3239 "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
3152 "dev": true 3240 "dev": true
3153 }, 3241 },
3242 + "delayed-stream": {
3243 + "version": "1.0.0",
3244 + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
3245 + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
3246 + },
3154 "denque": { 3247 "denque": {
3155 "version": "2.0.1", 3248 "version": "2.0.1",
3156 "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", 3249 "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
...@@ -3349,6 +3442,21 @@ ...@@ -3349,6 +3442,21 @@
3349 "unpipe": "~1.0.0" 3442 "unpipe": "~1.0.0"
3350 } 3443 }
3351 }, 3444 },
3445 + "follow-redirects": {
3446 + "version": "1.15.1",
3447 + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
3448 + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
3449 + },
3450 + "form-data": {
3451 + "version": "4.0.0",
3452 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
3453 + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
3454 + "requires": {
3455 + "asynckit": "^0.4.0",
3456 + "combined-stream": "^1.0.8",
3457 + "mime-types": "^2.1.12"
3458 + }
3459 + },
3352 "forwarded": { 3460 "forwarded": {
3353 "version": "0.2.0", 3461 "version": "0.2.0",
3354 "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 3462 "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 "author": "황선혁", 16 "author": "황선혁",
17 "license": "MIT", 17 "license": "MIT",
18 "dependencies": { 18 "dependencies": {
19 + "axios": "^0.27.2",
19 "bcryptjs": "^2.4.3", 20 "bcryptjs": "^2.4.3",
20 "colors": "^1.4.0", 21 "colors": "^1.4.0",
21 "cors": "^2.8.5", 22 "cors": "^2.8.5",
......
1 +const express = require("express");
2 +const router = express.Router();
3 +const {
4 + getWeather,
5 + getForecast,
6 + getAirPollution,
7 +} = require("../actions/weatherActions");
8 +
9 +// "/api/weather/"
10 +router.post("/", getWeather);
11 +router.get("/forecast", getForecast);
12 +router.get("/airpollution", getAirPollution);
13 +
14 +module.exports = router;
...@@ -13,6 +13,7 @@ app.use(express.json()); ...@@ -13,6 +13,7 @@ app.use(express.json());
13 app.use(express.urlencoded({ extended: false })); 13 app.use(express.urlencoded({ extended: false }));
14 14
15 app.use("/api/users", require("./routes/userRoutes")); 15 app.use("/api/users", require("./routes/userRoutes"));
16 +app.use("/api/weather", require("./routes/weatherRoutes"));
16 17
17 app.use(errorHandler); 18 app.use(errorHandler);
18 19
......