diff --git a/assignments/hackyourtemperature_W2/.gitignore b/assignments/hackyourtemperature_W2/.gitignore new file mode 100644 index 000000000..0c2ad0902 --- /dev/null +++ b/assignments/hackyourtemperature_W2/.gitignore @@ -0,0 +1 @@ +.env diff --git a/assignments/hackyourtemperature_W2/__tests__/app.test.js b/assignments/hackyourtemperature_W2/__tests__/app.test.js new file mode 100644 index 000000000..81f49b483 --- /dev/null +++ b/assignments/hackyourtemperature_W2/__tests__/app.test.js @@ -0,0 +1,24 @@ +import app from "../app.js"; +import supertest from "supertest"; + +const request = supertest(app); + +describe("POST /weather", () => { + it("should return 400 if cityName is missing", async () => { + const res = await request.post("/weather").send({}); + expect(res.status).toBe(400); + expect(res.body.weatherText).toBe("cityName is required"); + }); + + it("should return 404 if cityName is invalid", async () => { + const res = await request.post("/weather").send({ cityName: "InvalidCity123" }); + expect(res.status).toBe(404); + expect(res.body.weatherText).toBe("City is not found!"); + }); + + it("should return temperature if cityName is valid", async () => { + const res = await request.post("/weather").send({ cityName: "Amsterdam" }); + expect(res.status).toBe(200); + expect(res.body.weatherText).toContain("The temperature in Amsterdam is"); + }); +}); diff --git a/assignments/hackyourtemperature_W2/app.js b/assignments/hackyourtemperature_W2/app.js new file mode 100644 index 000000000..fd65832b1 --- /dev/null +++ b/assignments/hackyourtemperature_W2/app.js @@ -0,0 +1,43 @@ +import express from "express"; +import keys from "./sources/keys.js"; + +const app = express(); +app.use(express.json()); + +// Проверка работы сервера === test route +app.get("/", (req, res) => { + res.send("hello from backend to frontend!"); +}); + +// Получение погоды по названию города === get weather by city name +app.post("/weather", async (req, res) => { + const cityName = req.body.cityName; + + // Если город не указан === if city is not provided + if (!cityName) { + return res.status(400).json({ weatherText: "cityName is required" }); + } + + try { + // Запрос к OpenWeather API === request to OpenWeather API + const response = await fetch( + `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${keys.API_KEY}&units=metric` + ); + const data = await response.json(); + + // Если город не найден === if city is not found + if (data.cod !== 200) { + return res.status(404).json({ weatherText: "City is not found!" }); + } + + // Отправка температуры пользователю === send temperature to user + const temperature = data.main.temp; + res.json({ weatherText: `The temperature in ${data.name} is ${temperature}°C` }); + } catch (error) { + // Ошибка сервера === server error + res.status(500).json({ weatherText: "Server error!" }); + } +}); + +// Экспорт для тестов и сервера === export for tests and server +export default app; diff --git a/assignments/hackyourtemperature_W2/babel.config.cjs b/assignments/hackyourtemperature_W2/babel.config.cjs new file mode 100644 index 000000000..630a59460 --- /dev/null +++ b/assignments/hackyourtemperature_W2/babel.config.cjs @@ -0,0 +1,12 @@ +module.exports = { + presets: [ + [ + "@babel/preset-env", + { + targets: { + node: "current" // чтобы Jest понимал текущую версию Node === for Jest to understand the current Node version + } + } + ] + ] +}; diff --git a/assignments/hackyourtemperature_W2/package.json b/assignments/hackyourtemperature_W2/package.json new file mode 100644 index 000000000..6bfdd54c0 --- /dev/null +++ b/assignments/hackyourtemperature_W2/package.json @@ -0,0 +1,27 @@ +{ + "name": "hackyourtemperature_w2", + "version": "1.0.0", + "type": "module", + "main": "index.js", + "scripts": { + "test": "jest", + "start": "node server.js", + "dev": "nodemon server.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "dotenv": "^17.2.3", + "express": "^5.1.0", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "@babel/preset-env": "^7.28.5", + "babel-jest": "^30.2.0", + "jest": "^30.2.0", + "nodemon": "^3.1.10", + "supertest": "^7.1.4" + } +} diff --git a/assignments/hackyourtemperature_W2/server.js b/assignments/hackyourtemperature_W2/server.js new file mode 100644 index 000000000..496d716cb --- /dev/null +++ b/assignments/hackyourtemperature_W2/server.js @@ -0,0 +1,4 @@ +import app from "./app.js"; +// Start the server === don't add funktionality in this file +const PORT = 3000; +app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`)); diff --git a/assignments/hackyourtemperature_W2/sources/keys.js b/assignments/hackyourtemperature_W2/sources/keys.js new file mode 100644 index 000000000..75908b54e --- /dev/null +++ b/assignments/hackyourtemperature_W2/sources/keys.js @@ -0,0 +1,9 @@ +// sources/keys.js +import dotenv from "dotenv"; +dotenv.config(); // Загружает переменные из .env === loads variables from .env + +const keys = { + API_KEY: process.env.API_KEY || "" // fallback на пустую строку === fallback to empty string +}; + +export default keys;