diff --git a/assignments/hackyourtemperature/__tests__/app.test.js b/assignments/hackyourtemperature/__tests__/app.test.js new file mode 100644 index 000000000..cacab267b --- /dev/null +++ b/assignments/hackyourtemperature/__tests__/app.test.js @@ -0,0 +1,66 @@ +import app from "../app.js"; +import supertest from "supertest"; + +const request = supertest(app); + +describe("POST /", () => { + it("Quick test", () => { + expect(1).toBe(1); + }); +}); + +describe("GET /", () => { + it("Should return welcome text and status 200", async () => { + const response = await request.get("/"); + expect(response.status).toBe(200); + expect(response.text).toBe("hello from backend to frontend!"); + }); +}); + +describe("POST /weather", () => { + it("should return a 404 status code if city is not provided", async () => { + const response = await request.post("/weather").send({}); + + expect(response.status).toBe(404); + }); +}); + +describe("POST /weather", () => { + it("should return a 200 status code if city is provided", async () => { + const response = await request + .post("/weather") + .send({ cityName: "Addis Ababa" }); + + expect(response.status).toBe(200); + }); +}); + +describe("POST /weather", () => { + it("should return a 200 status code if city is provided and weather text", async () => { + const response = await request + .post("/weather") + .send({ cityName: "Addis Ababa" }); + + expect(response.status).toBe(200); + expect(response.body).toHaveProperty("weatherText"); + expect(response.body.weatherText).toContain("Addis Ababa"); + }); +}); + +describe("POST /weather", () => { + it("should return a 500 status code if city is not found", async () => { + const response = await request + .post("/weather") + .send({ cityName: "Addis Ababa!" }); + + expect(response.status).toBe(500); + expect(response.body).toHaveProperty("weatherText"); + expect(response.body.weatherText).toContain("City not found: Addis Ababa!"); + }); +}); +describe("GET /nonexistent", () => { + it("should return a 404 status code for non-existent routes", async () => { + const response = await request.get("/nonexistent"); + expect(response.status).toBe(404); + }); +}); diff --git a/assignments/hackyourtemperature/app.js b/assignments/hackyourtemperature/app.js new file mode 100644 index 000000000..05bc11e97 --- /dev/null +++ b/assignments/hackyourtemperature/app.js @@ -0,0 +1,37 @@ +import express from "express"; +import fetch from "node-fetch"; +import keys from "./sources/keys.js"; +const app = express(); + +app.use(express.json()); + +app.post("/weather", async (req, res) => { + let { cityName } = req.body; + const apiUrl = `https://api.openweathermap.org/data/2.5/weather?&q=${cityName}&appid=${keys.API_KEY}`; + if (!cityName) { + return res.status(404).send("You need to provide a city name"); + } + try { + const response = await fetch(apiUrl); + if (!response.ok) { + throw new Error("API not found "); + } + const data = await response.json(); + const temp = data.main.temp; + const tempCelsius = temp - 273.15; + data.main.temp = tempCelsius; + res.send({ + weatherText: `The weather in ${cityName} is ${tempCelsius.toFixed( + 0 + )} degrees Celsius.`, + }); + } catch { + res.status(500).send({ weatherText: `City not found: ${cityName}` }); + } +}); + +app.get("/", (req, res) => { + res.send("hello from backend to frontend!"); +}); + +export default app; diff --git a/assignments/hackyourtemperature/babel.config.cjs b/assignments/hackyourtemperature/babel.config.cjs new file mode 100644 index 000000000..fbb629af6 --- /dev/null +++ b/assignments/hackyourtemperature/babel.config.cjs @@ -0,0 +1,13 @@ +module.exports = { + presets: [ + [ + // This is a configuration, here we are telling babel what configuration to use + "@babel/preset-env", + { + targets: { + node: "current", + }, + }, + ], + ], +}; diff --git a/assignments/hackyourtemperature/jest.config.js b/assignments/hackyourtemperature/jest.config.js new file mode 100644 index 000000000..19ba9649e --- /dev/null +++ b/assignments/hackyourtemperature/jest.config.js @@ -0,0 +1,8 @@ +export default { + // Tells jest that any file that has 2 .'s in it and ends with either js or jsx should be run through the babel-jest transformer + transform: { + "^.+\\.jsx?$": "babel-jest", + }, + // By default our `node_modules` folder is ignored by jest, this tells jest to transform those as well + transformIgnorePatterns: [], +}; diff --git a/assignments/hackyourtemperature/package.json b/assignments/hackyourtemperature/package.json new file mode 100644 index 000000000..bc799b767 --- /dev/null +++ b/assignments/hackyourtemperature/package.json @@ -0,0 +1,27 @@ +{ + "name": "hackyourtemperature", + "version": "1.0.0", + "main": "server.js", + "scripts": { + "test": "jest", + "start": "node server.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "express": "^4.21.2", + "express-handlebars": "^8.0.1", + "node-fetch": "^3.3.2", + "nodemon": "^3.1.9" + }, + "type": "module", + "devDependencies": { + "@babel/core": "^7.26.9", + "@babel/preset-env": "^7.26.9", + "babel-jest": "^29.7.0", + "jest": "^29.7.0", + "supertest": "^7.0.0" + } +} diff --git a/assignments/hackyourtemperature/server.js b/assignments/hackyourtemperature/server.js new file mode 100644 index 000000000..256e1dbf7 --- /dev/null +++ b/assignments/hackyourtemperature/server.js @@ -0,0 +1,5 @@ +import app from "./app.js"; +const port = 3000; +app.listen(port, () => { + console.log(`listening from server at port ${port}`); +}); diff --git a/assignments/hackyourtemperature/sources/Keys.js b/assignments/hackyourtemperature/sources/Keys.js new file mode 100644 index 000000000..d3f72cf57 --- /dev/null +++ b/assignments/hackyourtemperature/sources/Keys.js @@ -0,0 +1,5 @@ +const keys = { + API_KEY: "b5dc5a484bf9f57400737317aeaf6e7f", +}; + +export default keys; diff --git a/week2/prep-exercises/1-blog-API/package.json b/week2/prep-exercises/1-blog-API/package.json index d89c4bd76..148b0796a 100644 --- a/week2/prep-exercises/1-blog-API/package.json +++ b/week2/prep-exercises/1-blog-API/package.json @@ -10,6 +10,6 @@ "author": "", "license": "ISC", "dependencies": { - "express": "^4.17.1" + "express": "^4.21.2" } } diff --git a/week2/prep-exercises/1-blog-API/server.js b/week2/prep-exercises/1-blog-API/server.js index 3f615e8f5..f4e67b11e 100644 --- a/week2/prep-exercises/1-blog-API/server.js +++ b/week2/prep-exercises/1-blog-API/server.js @@ -1,10 +1,51 @@ -const express = require('express') +const express = require("express"); 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 +const fs = require("fs"); +app.use(express.json()); + +app.get("/", function (req, res) { + res.send("Hello World"); +}); + +//creating a blog +app.post("/blogs", (req, res) => { + const { title, content } = req.body; + fs.writeFileSync(title, content); + res.end("ok"); +}); + +// updating a blog +app.put("/blogs/:title", (req, res) => { + const { title } = req.params; + const { content } = req.body; + if (fs.existsSync(title)) { + fs.writeFileSync(title, content); + res.end("ok"); + } else { + res.status(404).send("This blog does not exist!"); + } +}); + +//deleting a blog +app.delete("/blogs/:title", (req, res) => { + const { title } = req.params; + if (fs.existsSync(title)) { + fs.unlinkSync(title); + res.end("ok"); + } else { + res.status(404).send("This blog does not exist!"); + } +}); + +//serving a blog +app.get("/blogs/:title", (req, res) => { + const { title } = req.params; + if (fs.existsSync(title)) { + const blogContent = fs.readFileSync(title, "utf8"); + res.send(blogContent); + } else { + res.status(404).send("This blog does not exist!"); + } +}); + +app.listen(3000);