diff --git a/.gitignore b/.gitignore index b6b402ed9..37a7f2f66 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules npm-debug.log package-lock.json yarn-error.log +.env *.bkp week3/prep-exercise/server-demo/ diff --git a/assignments/config-files/babel.config.cjs b/assignments/babel.config.cjs similarity index 100% rename from assignments/config-files/babel.config.cjs rename to assignments/babel.config.cjs diff --git a/assignments/hackyourtemperature/__tests__/app.test.js b/assignments/hackyourtemperature/__tests__/app.test.js new file mode 100644 index 000000000..cd5014600 --- /dev/null +++ b/assignments/hackyourtemperature/__tests__/app.test.js @@ -0,0 +1,29 @@ +import { app } from '../app.js'; +import supertest from 'supertest'; + +const request = supertest(app); + +describe('POST /weather', () => { + it('should return 400 if no cityName is provided', async () => { + const response = await request.post('/weather').send({}); + + expect(response.status).toBe(400); + expect(response.body).toEqual({ + weatherText: 'City name is required!' + }); + }); + + it('should return 404 if cityName is gibberish', async () => { + const response = await request.post('/weather').send({ cityName: 'aslkdjflaskjd' }); + + expect(response.status).toBe(404); + expect(response.body).toEqual({ weatherText: 'City is not found!' }); + }); + + it('should return 200 with correct cityName', async () => { + const response = await request.post('/weather').send({ cityName: 'Amsterdam' }); + + expect(response.status).toBe(200); + expect(response.body.weatherText).toContain('Amsterdam'); + }); +}); \ No newline at end of file diff --git a/assignments/hackyourtemperature/app.js b/assignments/hackyourtemperature/app.js new file mode 100644 index 000000000..b7223ded9 --- /dev/null +++ b/assignments/hackyourtemperature/app.js @@ -0,0 +1,40 @@ +import express from 'express'; +import keys from './sources/keys.js'; +import fetch from 'node-fetch'; + +const app = express(); + +app.use(express.json()); + +app.get('/', (req, res) => { + res.send('Hello from backend to frontend!'); +}); + +app.post('/weather', async (req, res) => { + try { + const { cityName } = req.body; + + if (!cityName) { + return res.status(400).json({ weatherText: 'City name is required!' }); + } + + const response = await fetch( + `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${keys.API_KEY}` + ); + + if (!response.ok) { + return res.status(404).json({ weatherText: 'City is not found!' }); + } + + const data = await response.json(); + const temperatureInCelsius = Math.floor(data.main.temp - 273.15); + + res.status(200).json({ + weatherText: `${cityName}: ${temperatureInCelsius}°C` + }); + } catch (error) { + res.status(500).json({ error: 'Internal server error' }); + } +}); + +export { app }; \ No newline at end of file diff --git a/assignments/hackyourtemperature/babel.config.cjs b/assignments/hackyourtemperature/babel.config.cjs new file mode 100644 index 000000000..e8253c874 --- /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' + } + } + ] + ] +}; \ No newline at end of file diff --git a/assignments/hackyourtemperature/jest.config.js b/assignments/hackyourtemperature/jest.config.js new file mode 100644 index 000000000..7e0d50f98 --- /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: [] +}; \ No newline at end of file diff --git a/assignments/hackyourtemperature/package.json b/assignments/hackyourtemperature/package.json new file mode 100644 index 000000000..f9cd5ec9a --- /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": { + "dotenv": "^16.4.7", + "express": "^4.21.1", + "express-handlebars": "^8.0.1", + "node-fetch": "^3.3.2" + }, + "type": "module", + "devDependencies": { + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "babel-jest": "^29.7.0", + "jest": "^29.7.0", + "supertest": "^7.0.0" + } +} \ No newline at end of file diff --git a/assignments/hackyourtemperature/server.js b/assignments/hackyourtemperature/server.js new file mode 100644 index 000000000..c0b9667f4 --- /dev/null +++ b/assignments/hackyourtemperature/server.js @@ -0,0 +1,7 @@ +import { app } from './app.js'; + +const port = 3000; + +app.listen(port, () => { + console.log(`App listening on port ${port}`); +}); \ No newline at end of file diff --git a/assignments/hackyourtemperature/sources/keys.js b/assignments/hackyourtemperature/sources/keys.js new file mode 100644 index 000000000..5ebe16e9e --- /dev/null +++ b/assignments/hackyourtemperature/sources/keys.js @@ -0,0 +1,8 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +const keys = { + API_KEY: process.env.API_KEY, +}; + +export default keys; diff --git a/assignments/config-files/jest.config.js b/assignments/jest.config.js similarity index 100% rename from assignments/config-files/jest.config.js rename to assignments/jest.config.js