diff --git a/.gitignore b/.gitignore index b6b402ed9..f4cf08a7e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ yarn-error.log *.bkp week3/prep-exercise/server-demo/ +assignments/hackyourtemperature/sources/keys.js diff --git a/assignments/hackyourtemperature/__tests__/app.test.js b/assignments/hackyourtemperature/__tests__/app.test.js new file mode 100644 index 000000000..b09f26dfe --- /dev/null +++ b/assignments/hackyourtemperature/__tests__/app.test.js @@ -0,0 +1,28 @@ +import app from "../app.js"; +import supertest from "supertest"; + +const request = supertest(app); + +describe("POST /weather", () => { + it("should return temperature for a valid city", async () => { + const response = await request + .post("/weather") + .send({ cityName: "Amsterdam" }); + expect(response.status).toBe(200); + expect(response.body.weatherText).toContain("Amsterdam"); + }); + + it("should return error message for an invalid city", async () => { + const response = await request + .post("/weather") + .send({ cityName: "InvalidCity" }); + expect(response.status).toBe(404); + expect(response.body.weatherText).toBe("City is not found!"); + }); + + it("should return error for missing city name", async () => { + const response = await request.post("/weather").send({}); + expect(response.status).toBe(400); + expect(response.body.error).toBe("City name is required."); + }); +}); diff --git a/assignments/hackyourtemperature/app.js b/assignments/hackyourtemperature/app.js new file mode 100644 index 000000000..9e6832492 --- /dev/null +++ b/assignments/hackyourtemperature/app.js @@ -0,0 +1,44 @@ +import express from "express"; +import fetch from "node-fetch"; +import { API_KEY } from "./sources/keys.js"; + +export const app = express(); + +app.use(express.json()); + +app.get("/", (req, res) => { + res.send("Welcome to the Weather App!"); +}); + +app.post("/weather", async (req, res) => { + const cityName = req.body.cityName; + + if (!cityName) { + return res.status(400).json({ weatherText: "City name is required!" }); + } + + try { + const weatherData = await getWeatherData(cityName); + + if (weatherData.cod !== 200) { + const errorMessage = + weatherData.cod === "404" ? "City is not found!" : weatherData.message; + + return res.status(weatherData.cod).json({ weatherText: errorMessage }); + } + + const temp = weatherData.main.temp; + return res + .status(200) + .json({ weatherText: `The weather in ${cityName} is ${temp}°C` }); + } catch (error) { + return res.status(500).json({ weatherText: "Something went wrong!" }); + } +}); + +const getWeatherData = async (cityName) => { + const response = await fetch( + `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&APPID=${API_KEY}&units=metric` + ); + return await response.json(); +}; diff --git a/assignments/hackyourtemperature/package.json b/assignments/hackyourtemperature/package.json new file mode 100644 index 000000000..e6015d81c --- /dev/null +++ b/assignments/hackyourtemperature/package.json @@ -0,0 +1,27 @@ +{ + "name": "hackyourtemperature", + "version": "1.0.0", + "description": "> If you are following the HackYourFuture curriculum we recommend you to start with module 1: [HTML/CSS/GIT](https://github.com/HackYourFuture/HTML-CSS). To get a complete overview of the HackYourFuture curriculum first, click [here](https://github.com/HackYourFuture/curriculum).", + "main": "index.js", + "type": "module", + "scripts": { + "test": "jest", + "start": "node server.js", + "dev": "nodemon server.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.21.0", + "express-handlebars": "^8.0.1", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "nodemon": "^3.1.7", + "jest": "^29.0.0", + "supertest": "^6.3.3", + "babel-jest": "^29.0.0", + "@babel/preset-env": "^7.20.0" + } +} diff --git a/assignments/hackyourtemperature/server.js b/assignments/hackyourtemperature/server.js new file mode 100644 index 000000000..004412ff0 --- /dev/null +++ b/assignments/hackyourtemperature/server.js @@ -0,0 +1,7 @@ +import { app } from "./app.js"; + +const PORT = process.env.PORT || 3000; + +app.listen(PORT, () => { + console.log(`Server is running on http://localhost:${PORT}`); +}); diff --git a/package.json b/package.json new file mode 100644 index 000000000..6010a1480 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "express": "^4.21.0" + } +} diff --git a/week2/prep-exercises/1-blog-API/server.js b/week2/prep-exercises/1-blog-API/server.js index 3f615e8f5..a1e59abed 100644 --- a/week2/prep-exercises/1-blog-API/server.js +++ b/week2/prep-exercises/1-blog-API/server.js @@ -1,10 +1,92 @@ -const express = require('express') +const express = require("express"); +const fs = require("fs"); const app = express(); - - -// YOUR CODE GOES IN HERE -app.get('/', function (req, res) { - res.send('Hello World') -}) - -app.listen(3000) \ No newline at end of file + +app.use(express.json()); + +app.get("/", (req, res) => { + res.send("You have built you API 🎉"); +}); + +app.post("/blogs", (req, res) => { + const { title, content } = req.body; + + if (!title || !content) { + return res.status(400).send("Title and content are required"); + } + + try { + fs.writeFileSync(`./${title}.txt`, content); + res.status(201).send("Blog created"); + } catch (err) { + res.status(500).send("An error occurred while creating the blog"); + } +}); + +app.put("/blogs/:title", (req, res) => { + const { title } = req.params; + const { content } = req.body; + + if (!content) { + return res.status(400).send("Content is required"); + } + + if (fs.existsSync(`./${title}.txt`)) { + try { + fs.writeFileSync(`./${title}.txt`, content); + res.send("Blog updated"); + } catch (err) { + res.status(500).send("An error occurred while updating the blog"); + } + } else { + res.status(404).send("This post does not exist!"); + } +}); + +app.delete("/blogs/:title", (req, res) => { + const { title } = req.params; + + if (fs.existsSync(`./${title}.txt`)) { + try { + fs.unlinkSync(`./${title}.txt`); + res.send("Blog deleted"); + } catch (err) { + res.status(500).send("An error occurred while deleting the blog"); + } + } else { + res.status(404).send("This post does not exist!"); + } +}); + +app.get("/blogs/:title", (req, res) => { + const { title } = req.params; + + if (fs.existsSync(`./${title}.txt`)) { + try { + const content = fs.readFileSync(`./${title}.txt`, "utf8"); + res.send(content); + } catch (err) { + res.status(500).send("An error occurred while reading the blog"); + } + } else { + res.status(404).send("This post does not exist!"); + } +}); + +app.get("/blogs", (req, res) => { + try { + const files = fs.readdirSync("./"); + const blogs = files + .filter((file) => file.endsWith(".txt")) + .map((file) => ({ + title: file.replace(".txt", ""), + })); + res.json(blogs); + } catch (err) { + res.status(500).send("An error occurred while reading the blogs"); + } +}); + +app.listen(3000, () => { + console.log("Server is running on http://localhost:3000"); +});