Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions assignments/hackyourtemperature/__tests__/app.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import app from "../app.js";
import supertest from "supertest";

jest.setTimeout(20000);
const request = supertest(app);

describe("POST /weather", () => {
it("Quick test", () => expect(1).toBe(1));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the real tests added, this placeholder could be removed to reduce the noise.


it("400 no cityName", async () => {
const res = await request.post("/weather").send({});
expect(res.status).toBe(400);
expect(res.body.weatherText).toContain("Please provide a cityName");
});

it("404", async () => {
const res = await request
.post("/weather")
.send({ cityName: "asldkfjasldkfj" });
expect(res.status).toBe(404);
expect(res.body.weatherText).toBe("City is not found!");
});

it("200 °C", async () => {
const res = await request.post("/weather").send({ cityName: "Amsterdam" });
expect(res.status).toBe(200);
expect(res.body.weatherText).toEqual(expect.stringContaining("Amsterdam"));
expect(res.body.weatherText).toEqual(expect.stringContaining("°C"));
});
});
45 changes: 45 additions & 0 deletions assignments/hackyourtemperature/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import express from "express";
import keys from "./sources/keys.js";

const app = express();
app.use(express.json());

app.get("/", (req, res) => {
res.type("text").send("hello from backend to frontend!");
});

app.post("/weather", async (req, res) => {
const { cityName } = req.body ?? {};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the nullish coalescing is a great practice for defensive programming, but note that the express.json() middleware, the res.body will always be at least an empty object, so it's not necessary here.

if (!cityName || typeof cityName !== "string" || !cityName.trim()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done with the thorough input validation!

return res.status(400).json({ weatherText: "Please provide a cityName." });
}

const url = `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that you are using encodeURIComponent to properly encode the city name in the URL!

cityName
)}&units=metric&appid=${keys.API_KEY}`;

try {
const r = await fetch(url);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: A more descriptive name of the variable would be handy.

const data = await r.json();

if (!r.ok || String(data.cod) !== "200") {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great that you're checking the value of the data.cod value; I don't think I've seen anyone do this before!
I'm not that familiar with the API, but it seems a bit of a leap from the code not being '200' to concluding that it's a 404, city not found response, though. A more robust approach would be reading the cod value and returning the actual code the API provided.

return res.status(404).json({ weatherText: "City is not found!" });
}

const name = data?.name ?? cityName;
const temp = data?.main?.temp;
Comment on lines +29 to +30
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of the optional chaining for safe property access 👍


return res
.status(200)
.json({
weatherText: `The current temperature in ${name} is ${Math.round(
temp
)}°C.`,
});
} catch (e) {
console.error(e);
return res.status(500).json({ weatherText: "Server error." });
}
});

export default app;
19 changes: 19 additions & 0 deletions assignments/hackyourtemperature/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "hackyourtemperature",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node server.js",
"test": "jest"
},
"dependencies": {
"express": "^5.1.0",
"node-fetch": "^3.3.2"
},
"devDependencies": {
"@babel/preset-env": "^7.28.5",
"babel-jest": "^29.7.0",
"jest": "^29.7.0",
"supertest": "^6.3.4"
}
}
6 changes: 6 additions & 0 deletions assignments/hackyourtemperature/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import app from "./app.js";

const PORT = process.env.PORT || 3009;
app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
});
5 changes: 5 additions & 0 deletions assignments/hackyourtemperature/sources/keys.js
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the project instructions don't mention this, but as a note for future projects, avoid committing API secrets to GitHub repositories. It's better to store them as environment variables, for example.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const keys = {
API_KEY: "60238be831d8710a4f2928681949b036"
};

export default keys;
1 change: 1 addition & 0 deletions week2/prep-exercises/1-blog-API/My first blog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world!
7 changes: 4 additions & 3 deletions week2/prep-exercises/1-blog-API/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "1-blog-api",
"version": "1.0.0",
"description": "",
"description": "Anyone here still remember blogs!? They were all the rage around 10 years ago. We are a bit late to the party, but I think we can still make some money with a blog application.",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
Expand All @@ -10,6 +10,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
}
"express": "^4.21.2"
},
"keywords": []
}
69 changes: 64 additions & 5 deletions week2/prep-exercises/1-blog-API/server.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,69 @@
const express = require('express')
const express = require('express');
const fs = require('fs');
const app = express();


// YOUR CODE GOES IN HERE
app.use(express.json());

app.delete('/blogs/:title', (req, res) => {
const title = req.params.title;
const filePath = `${title}.txt`;

if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
res.send('ok');
} else {
res.status(404).send('This post does not exist!');
}
});

app.put('/blogs/:title', (req, res) => {
const title = req.params.title;
const { content } = req.body;

if (!content) {
return res.status(400).send('Missing content');
}

const filePath = `${title}.txt`;

if (fs.existsSync(filePath)) {
fs.writeFileSync(filePath, content);
res.send('ok');
} else {
res.status(404).send('This post does not exist!');
}
});


app.post('/blogs', (req, res) => {
const { title, content } = req.body;

if (!title || !content) {
return res.status(400).send('Missing title or content');
}

fs.writeFileSync(`${title}.txt`, content);

res.end('ok');
});



app.get('/blogs/:title', (req, res) => {
const title = req.params.title;
const filePath = `${title}.txt`;

if (fs.existsSync(filePath)) {
const post = fs.readFileSync(filePath, 'utf-8');
res.send(post);
} else {
res.status(404).send('This post does not exist!');
}
});

app.get('/', function (req, res) {
res.send('Hello World')
})

app.listen(3000)


app.listen(3000, () => console.log('Server running on http://localhost:3000'));