diff --git a/hackyourtemperature/__tests__/app.test.js b/hackyourtemperature/__tests__/app.test.js
new file mode 100644
index 000000000..e169111ef
--- /dev/null
+++ b/hackyourtemperature/__tests__/app.test.js
@@ -0,0 +1,45 @@
+import app from '../app.js'
+import supertest from 'supertest'
+import fetch from 'node-fetch'
+
+jest.mock('node-fetch', () => jest.fn())
+
+const request = supertest(app)
+
+describe('POST /', () => {
+ it('returns temperature for a valid city', async () => {
+ const fakeGeoData = [{ lat: 52.37, lon: 4.89 }]
+ const fakeWeatherData = {
+ main: {
+ temp: 283.15,
+ },
+ }
+
+ fetch
+ .mockResolvedValueOnce({
+ json: async () => fakeGeoData,
+ })
+ .mockResolvedValueOnce({
+ json: async () => fakeWeatherData,
+ })
+
+ const response = await request.post('/').send({ cityName: 'Amsterdam' })
+
+ expect(response.statusCode).toBe(200)
+ expect(response.body).toEqual({
+ cityName: 'Amsterdam',
+ temperature: '10.0',
+ })
+ })
+
+ it('returns error message for unknown city', async () => {
+ fetch.mockResolvedValueOnce({
+ json: async () => [],
+ })
+
+ const response = await request.post('/').send({ cityName: 'FakeCityXYZ' })
+
+ expect(response.statusCode).toBe(200)
+ expect(response.body).toBe('City is not found')
+ })
+})
diff --git a/hackyourtemperature/app.js b/hackyourtemperature/app.js
new file mode 100644
index 000000000..f8c7c52ec
--- /dev/null
+++ b/hackyourtemperature/app.js
@@ -0,0 +1,48 @@
+import express from 'express'
+import { engine } from 'express-handlebars'
+import fetch from 'node-fetch'
+import { API_KEY } from './sources/keys.js'
+
+
+const app = express()
+
+app.engine('handlebars', engine())
+app.set('view engine', 'handlebars')
+app.set('views', './views')
+
+app.get('/', (req, res) => {
+ res.render('home')
+})
+
+app.use(express.json())
+
+app.post('/', async (req, res) => {
+ try {
+ const cityName = req.body.cityName
+ const geoData = await fetch(
+ `http://api.openweathermap.org/geo/1.0/direct?q=${cityName}&limit=1&appid=${API_KEY}`
+ )
+ const geoResponse = await geoData.json()
+ console.log(geoResponse)
+ if (geoResponse.length == 0) {
+ throw new Error('City is not found')
+ }
+
+ const lat = geoResponse[0].lat
+ const lon = geoResponse[0].lon
+ console.log(lat, lon)
+
+ const weatherData = await fetch(
+ `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}`
+ )
+ const weatherResponse = await weatherData.json()
+ res.json({
+ cityName: cityName,
+ temperature: (weatherResponse.main.temp - 273.15).toFixed(1)
+ });
+ } catch (err) {
+ res.json(err.message)
+ }
+})
+
+export default app
diff --git a/hackyourtemperature/babel.config.cjs b/hackyourtemperature/babel.config.cjs
new file mode 100644
index 000000000..fbb629af6
--- /dev/null
+++ b/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/hackyourtemperature/jest.config.js b/hackyourtemperature/jest.config.js
new file mode 100644
index 000000000..19ba9649e
--- /dev/null
+++ b/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/hackyourtemperature/package.json b/hackyourtemperature/package.json
new file mode 100644
index 000000000..2d7e556a0
--- /dev/null
+++ b/hackyourtemperature/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "hackyourtemperature",
+ "version": "1.0.0",
+ "main": "server.js",
+ "type": "module",
+ "scripts": {
+ "test": "jest",
+ "start": "node server.js",
+ "dev": "nodemon server.js"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "description": "",
+ "dependencies": {
+ "@babel/preset-env": "^7.27.2",
+ "babel-jest": "^29.7.0",
+ "express": "^5.1.0",
+ "express-handlebars": "^8.0.3",
+ "jest": "^29.7.0",
+ "node-fetch": "^3.3.2",
+ "nodemon": "^3.1.10",
+ "supertest": "^7.1.0"
+ }
+}
diff --git a/hackyourtemperature/server.js b/hackyourtemperature/server.js
new file mode 100644
index 000000000..9805cebc4
--- /dev/null
+++ b/hackyourtemperature/server.js
@@ -0,0 +1,5 @@
+import app from './app.js'
+
+app.listen(3000, () => {
+ console.log(`server started on http://localhost:3000`)
+})
diff --git a/hackyourtemperature/sources/keys.js b/hackyourtemperature/sources/keys.js
new file mode 100644
index 000000000..976b30002
--- /dev/null
+++ b/hackyourtemperature/sources/keys.js
@@ -0,0 +1 @@
+export const API_KEY = '7d47d5f41dcdf3b026655cb15bf3ff0a'
diff --git a/hackyourtemperature/views/home.handlebars b/hackyourtemperature/views/home.handlebars
new file mode 100644
index 000000000..e69de29bb
diff --git a/hackyourtemperature/views/layouts/main.handlebars b/hackyourtemperature/views/layouts/main.handlebars
new file mode 100644
index 000000000..87d24ab87
--- /dev/null
+++ b/hackyourtemperature/views/layouts/main.handlebars
@@ -0,0 +1 @@
+
Hello from backend to frontend!
\ No newline at end of file
diff --git a/week1/prep-exercises/1-web-server/server.js b/week1/prep-exercises/1-web-server/server.js
index 90cb5ee65..0ca2b6c30 100644
--- a/week1/prep-exercises/1-web-server/server.js
+++ b/week1/prep-exercises/1-web-server/server.js
@@ -1,14 +1,43 @@
/**
* Exercise 3: Create an HTTP web server
*/
-
-const http = require('http');
+const fs = require('fs').promises
+const path = require('path')
+const http = require('http')
//create a server
-let server = http.createServer(function (req, res) {
+let server = http.createServer(async function (req, res) {
// YOUR CODE GOES IN HERE
- res.write('Hello World!'); // Sends a response back to the client
- res.end(); // Ends the response
-});
+ try {
+ if (req.url === '/') {
+ const data = await fs.readFile(path.join(__dirname, 'index.html'))
+ res.writeHead(200, {
+ 'Content-Type': 'text/html',
+ })
+ res.end(data)
+ } else if (req.url === '/index.js') {
+ const data = await fs.readFile(path.join(__dirname, 'index.js'))
+ res.writeHead(200, {
+ 'Content-Type': 'application/javascript',
+ })
+ res.end(data)
+ } else {
+ res.writeHead(404, {
+ 'Content-Type': 'text/plain',
+ })
+ res.end('404 not found')
+ }
+ } catch (err) {
+ res.writeHead(500, {
+ 'Content-Type': 'text/plain',
+ })
+ res.end('server error')
+ console.error(err)
+ }
+ // res.write('Hello World!') // Sends a response back to the client
+ // res.end() // Ends the response
+})
-server.listen(3000); // The server starts to listen on port 3000
+server.listen(3000, () => {
+ console.log('server is running (listen on port 3000)')
+}) // The server starts to listen on port 3000
diff --git a/week2/practice-exercises/1-joke-api/package.json b/week2/practice-exercises/1-joke-api/package.json
new file mode 100644
index 000000000..798ac30b4
--- /dev/null
+++ b/week2/practice-exercises/1-joke-api/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "1-joke-api",
+ "type": "module",
+ "version": "1.0.0",
+ "description": "Did you know that there is an API for Chuck Norris jokes? That's incredible, right!?",
+ "main": "script.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "node-fetch": "^3.3.2"
+ }
+}
diff --git a/week2/practice-exercises/1-joke-api/script.js b/week2/practice-exercises/1-joke-api/script.js
index be4d84612..c0cddb830 100644
--- a/week2/practice-exercises/1-joke-api/script.js
+++ b/week2/practice-exercises/1-joke-api/script.js
@@ -1,18 +1,25 @@
/**
* 1. Chuck Norris programs do not accept input
- *
+ *
* `GET` a random joke inside the function, using the API: http://www.icndb.com/api/
- * (use `node-fetch`) and print it to the console.
+ * (use `node-fetch`) and print it to the console.
* Make use of `async/await` and `try/catch`
- *
+ *
* Hints
* - To install node dependencies you should first initialize npm
* - Print the entire response to the console to see how it is structured.
*/
+import fetch from 'node-fetch'
-function printChuckNorrisJoke() {
- // YOUR CODE GOES IN HERE
-
+async function printChuckNorrisJoke() {
+ try {
+ const response = await fetch('https://api.chucknorris.io/jokes/random')
+ // const body = await response.text()
+ const data = await response.json()
+ // console.log(response);
+ console.log(data.value)
+ } catch (err) {
+ console.error(err)
+ }
}
-
-printChuckNorrisJoke();
\ No newline at end of file
+printChuckNorrisJoke()
diff --git a/week2/prep-exercises/1-blog-API/My first blog b/week2/prep-exercises/1-blog-API/My first blog
new file mode 100644
index 000000000..e5d353447
--- /dev/null
+++ b/week2/prep-exercises/1-blog-API/My first blog
@@ -0,0 +1 @@
+Lorem ipsum
\ No newline at end of file
diff --git a/week2/prep-exercises/1-blog-API/package.json b/week2/prep-exercises/1-blog-API/package.json
index d89c4bd76..6ebc27dd3 100644
--- a/week2/prep-exercises/1-blog-API/package.json
+++ b/week2/prep-exercises/1-blog-API/package.json
@@ -5,11 +5,12 @@
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "start": "node server.js"
+ "start": "nodemon server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
- "express": "^4.17.1"
+ "express": "^4.17.1",
+ "nodemon": "^3.1.10"
}
}
diff --git a/week2/prep-exercises/1-blog-API/server.js b/week2/prep-exercises/1-blog-API/server.js
index 3f615e8f5..8bf3e3e75 100644
--- a/week2/prep-exercises/1-blog-API/server.js
+++ b/week2/prep-exercises/1-blog-API/server.js
@@ -1,10 +1,64 @@
const express = require('express')
-const app = express();
-
+const app = express()
+const fs = require('fs')
+
+app.use(express.json()) // to read requests format in JSON
+
+app.post('/blogs', (req, res) => {
+ // const content = req.body.content
+ // const title = req.body.title
+ const { title, content } = req.body
+ fs.writeFileSync(title, content)
+ res.end('ok')
+})
+
+app.put('/posts/:title', (req, res) => {
+ // console.log(req.query)
+ const { title, content } = req.body
+ if (title || content) {
+ if (fs.existsSync(title)) {
+ fs.writeFileSync(title, content)
+ res.end('ok')
+ } else {
+ res.end('This post does not exist!')
+ }
+ } else {
+ res.end('the request does not have a title and/or content')
+ }
+})
+
+app.delete('/blogs/:title', (req, res) => {
+ // console.log(req.params.title)
+ const title = req.params.title
+ if (fs.existsSync(title)) {
+ fs.unlinkSync(title);
+ res.end('ok');
+ } else {
+ res.end('This blog does not exist!')
+ }
+})
+
+app.get('/blogs/:title', (req, res) => {
+
+ // How to get the title from the url parameters?
+ const title = req.params.title
+ // check if post exists
+ if (fs.existsSync(title)) {
+ const post = fs.readFileSync(title);
+ res.end(`Your post content is: ${post}`)
+ } else {
+ res.end('This post does not exist!')
+ }
+
+
+ // send response
+})
// YOUR CODE GOES IN HERE
app.get('/', function (req, res) {
res.send('Hello World')
})
-
-app.listen(3000)
\ No newline at end of file
+
+app.listen(3000, () => {
+ console.log(`server started on http://localhost:3000`)
+})