From b9eb9f8f705ccd68d82fd488b007fd9192bb82a7 Mon Sep 17 00:00:00 2001 From: Philippe Torrel Date: Mon, 12 Oct 2026 11:17:01 +0200 Subject: [PATCH] --- .../tag26/01_website/backend/.env.example | 9 ++ .../tag26/01_website/backend/api.rest | 17 ++++ .../01_website/backend/models/ProductModel.js | 36 ++++++- .../01_website/backend/package-lock.json | 93 ++++++------------- .../tag26/01_website/backend/package.json | 6 +- .../01_website/backend/public/index.html | 2 +- .../tag26/01_website/backend/server.js | 60 +++++++----- 7 files changed, 133 insertions(+), 90 deletions(-) create mode 100644 04_browser-api/unterricht/tag26/01_website/backend/.env.example diff --git a/04_browser-api/unterricht/tag26/01_website/backend/.env.example b/04_browser-api/unterricht/tag26/01_website/backend/.env.example new file mode 100644 index 0000000..9e87490 --- /dev/null +++ b/04_browser-api/unterricht/tag26/01_website/backend/.env.example @@ -0,0 +1,9 @@ +# SERVER CONFIGURATION +SERVER_PORT=8000 +SERVER_HOST='127.0.0.1' + + +# API TOKENS +SECRET_KEY='top secret' +WEAHTER_API_KEY='' +JWT_TOKEN='' \ No newline at end of file diff --git a/04_browser-api/unterricht/tag26/01_website/backend/api.rest b/04_browser-api/unterricht/tag26/01_website/backend/api.rest index a72f66d..04b774a 100644 --- a/04_browser-api/unterricht/tag26/01_website/backend/api.rest +++ b/04_browser-api/unterricht/tag26/01_website/backend/api.rest @@ -22,4 +22,21 @@ Content-Type: application/json ### +# UPDATE Product + +PUT http://127.0.0.1:8000/api/products +Content-Type: application/json + +{ + "_id": "174a2a19-26eb-475e-af47-4f46d2ab62ec", + "position": 1, + "name": "UPDATED 3Doodler 3D Printing Pen", + "price": 39.99 +} + +### + +# DELETE Product + +DELETE http://127.0.0.1:8000/api/products/174a2a19-26eb-475e-af47-4f46d2ab62ec diff --git a/04_browser-api/unterricht/tag26/01_website/backend/models/ProductModel.js b/04_browser-api/unterricht/tag26/01_website/backend/models/ProductModel.js index b8dba20..92149db 100644 --- a/04_browser-api/unterricht/tag26/01_website/backend/models/ProductModel.js +++ b/04_browser-api/unterricht/tag26/01_website/backend/models/ProductModel.js @@ -32,7 +32,7 @@ const ProductModel = () => { const add = (product) => { const { name, price } = product; - // TODO: Validierung des Produkts + if (!hasAllProps(product)) return false; products.push({ _id: id(), @@ -44,11 +44,45 @@ const ProductModel = () => { return true; }; + const update = (product) => { + const foundIdx = products.findIndex((obj) => { + return obj._id === product._id; + }); + + // Guard + if (foundIdx === -1 || !hasAllProps(product)) return false; + + products[foundIdx] = product; + return true; + }; + + const remove = (id) => { + const foundIdx = products.findIndex((obj) => { + return obj._id === id; + }); + + // Guard + if (foundIdx === -1) return false; + + products.splice(foundIdx, 1); + + return true; + }; + + const hasAllProps = (product) => { + // return Object.hasOwn(product, 'name') && Object.hasOwn(product, 'price'); + + const keys = Object.keys(product); // ['name', 'price', ...] + return keys.includes('name') && keys.includes('price'); + }; + return { load, getAll, get, add, + update, + delete: remove, }; }; diff --git a/04_browser-api/unterricht/tag26/01_website/backend/package-lock.json b/04_browser-api/unterricht/tag26/01_website/backend/package-lock.json index 170ba44..6205c89 100644 --- a/04_browser-api/unterricht/tag26/01_website/backend/package-lock.json +++ b/04_browser-api/unterricht/tag26/01_website/backend/package-lock.json @@ -10,9 +10,9 @@ "dependencies": { "chalk": "^6.0.1", "cors": "^2.8.6", - "dotenv": "^18.0.6", - "express": "^5.2.1", - "uuid": "^14.0.2" + "dotenv": "^18.0.7", + "express": "^5.3.0", + "uuid": "^14.0.3" } }, "node_modules/accepts": { @@ -52,19 +52,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -116,9 +103,9 @@ } }, "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", + "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", "license": "MIT", "engines": { "node": ">=18" @@ -129,12 +116,16 @@ } }, "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cookie": { @@ -199,9 +190,9 @@ } }, "node_modules/dotenv": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.6.tgz", - "integrity": "sha512-ZMVmohV6CvAJtj++pZNyggluUt6hbRdQAxc2+Z635RL6/AG/ruXv5lHnybUFoxMPL/yrTL/tsF4paZu2l7RA6Q==", + "version": "18.0.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.7.tgz", + "integrity": "sha512-QEvMEF8ca3GNZJJnAbOgxpj5ULhBvnMcURp+XKrtvqFNPgjBvYoswQ0Jl2cO7JzCjxZjJhr9ZuIEhlrRxMft/Q==", "license": "BSD-2-Clause", "bin": { "dotenv": "dist/index.cjs" @@ -288,15 +279,15 @@ } }, "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.3.0.tgz", + "integrity": "sha512-qCqy1xSoaugxOD4IVHb1ZWdkvCF2W3aE2okKouWj8VwJ+ztskSiXoBnCSJqfKT+cVPJhuJqe9YLbY425+Zh00g==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", + "body-parser": "^2.3.0", + "content-disposition": "^2.0.1", + "content-type": "^2.0.0", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", @@ -312,14 +303,14 @@ "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", + "proxy-addr": "^2.0.8", + "qs": "^6.16.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", - "type-is": "^2.0.1", + "type-is": "^2.1.0", "vary": "^1.1.2" }, "engines": { @@ -589,19 +580,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/negotiator/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -905,19 +883,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/type-is/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -928,9 +893,9 @@ } }, "node_modules/uuid": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", - "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.3.tgz", + "integrity": "sha512-Sc5u1VVln93y1Xnz4R+CunOZc7R9LUcTmhj7Rc7Eg3HVcf7rVn2FOoa812fe0W8p3jD7xeoGSYbfqCGGH2B6xw==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" diff --git a/04_browser-api/unterricht/tag26/01_website/backend/package.json b/04_browser-api/unterricht/tag26/01_website/backend/package.json index c7269a9..d310a57 100644 --- a/04_browser-api/unterricht/tag26/01_website/backend/package.json +++ b/04_browser-api/unterricht/tag26/01_website/backend/package.json @@ -11,8 +11,8 @@ "dependencies": { "chalk": "^6.0.1", "cors": "^2.8.6", - "dotenv": "^18.0.6", - "express": "^5.2.1", - "uuid": "^14.0.2" + "dotenv": "^18.0.7", + "express": "^5.3.0", + "uuid": "^14.0.3" } } diff --git a/04_browser-api/unterricht/tag26/01_website/backend/public/index.html b/04_browser-api/unterricht/tag26/01_website/backend/public/index.html index e3dfdf3..3d3d7bb 100644 --- a/04_browser-api/unterricht/tag26/01_website/backend/public/index.html +++ b/04_browser-api/unterricht/tag26/01_website/backend/public/index.html @@ -10,7 +10,7 @@
-

Home

+

Expres Rest API

Server is running

diff --git a/04_browser-api/unterricht/tag26/01_website/backend/server.js b/04_browser-api/unterricht/tag26/01_website/backend/server.js index a40d340..7b2c74a 100644 --- a/04_browser-api/unterricht/tag26/01_website/backend/server.js +++ b/04_browser-api/unterricht/tag26/01_website/backend/server.js @@ -1,11 +1,14 @@ import express from 'express'; import color from 'chalk'; +import dotenv from 'dotenv'; + +dotenv.config(); // Sensible Konfigurationsvariablen werden in einer .env Datei ausgelagert // Models import ProductModel from './models/ProductModel.js'; -const PORT = 8000; -const HOST = '127.0.0.1'; +const PORT = process.env.SERVER_PORT || 8000; +const HOST = process.env.SERVER_HOST || '127.0.0.1'; const BASE_URL = `http://${HOST}:${PORT}`; // lade Produkte @@ -52,32 +55,47 @@ app.get('/api/products', (req, res) => { // B(R)EAD - read app.get('/api/products/:id', (req, res) => { const { id } = req.params; - const data = products.get(id); - return res.send(data); + const product = products.get(id); + + if (!product) { + return res.status(400).send({ msg: 'Could not get product', status: 400, success: false }); + } + + return res.send(product); }); -// +// HTTP - Methode - PUT/PATCH +// CR(U)D - update +// BR(E)AD - edit +app.put('/api/products', (req, res) => { + const product = req.body; + + const updated = products.update(product); + + if (!updated) { + return res.status(400).send({ msg: 'Could not update product', status: 400, success: false }); + } + + return res.send({ msg: 'Product updated', status: 200, success: true, data: product }); +}); + +// HTTP - Methode - DELETE +// CRU(D) - delete +// BREA(D) - delete +app.delete('/api/products/:id', (req, res) => { + const { id } = req.params; + + if (!products.delete(id)) { + return res.status(400).send({ msg: 'Could not delete product', status: 400, success: false }); + } + + return res.send({ msg: 'Product deleted', status: 200, success: true, data: id }); +}); app.get('/', (req, res) => { return res.send('Server is running!'); }); -app.get('/persons', (req, res) => { - console.log(req.method); // => 'GET' - // res.setHeader('Content-Type', 'application/json'); - // res.send( - // JSON.stringify([ - // { firstName: 'Max', lastName: 'Mustermann' }, - // { firstName: 'John', lastName: 'Wick' }, - // ]), - // ); - - return res.send([ - { firstName: 'Max', lastName: 'Mustermann' }, - { firstName: 'John', lastName: 'Wick' }, - ]); -}); - app.listen(PORT, HOST, () => { console.log(color.magenta(`Server is running at: ${BASE_URL}`)); console.log(color.yellow('To close: CTRL + C'));