This commit is contained in:
Philippe Torrel
2026-10-12 11:17:01 +02:00
parent 2c4aba89a9
commit b9eb9f8f70
7 changed files with 133 additions and 90 deletions
@@ -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=''
@@ -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
@@ -32,7 +32,7 @@ const ProductModel = () => {
const add = (product) => { const add = (product) => {
const { name, price } = product; const { name, price } = product;
// TODO: Validierung des Produkts if (!hasAllProps(product)) return false;
products.push({ products.push({
_id: id(), _id: id(),
@@ -44,11 +44,45 @@ const ProductModel = () => {
return true; 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 { return {
load, load,
getAll, getAll,
get, get,
add, add,
update,
delete: remove,
}; };
}; };
@@ -10,9 +10,9 @@
"dependencies": { "dependencies": {
"chalk": "^6.0.1", "chalk": "^6.0.1",
"cors": "^2.8.6", "cors": "^2.8.6",
"dotenv": "^18.0.6", "dotenv": "^18.0.7",
"express": "^5.2.1", "express": "^5.3.0",
"uuid": "^14.0.2" "uuid": "^14.0.3"
} }
}, },
"node_modules/accepts": { "node_modules/accepts": {
@@ -52,19 +52,6 @@
"url": "https://opencollective.com/express" "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": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -116,9 +103,9 @@
} }
}, },
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "1.1.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz",
"integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -129,12 +116,16 @@
} }
}, },
"node_modules/content-type": { "node_modules/content-type": {
"version": "1.0.5", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
} }
}, },
"node_modules/cookie": { "node_modules/cookie": {
@@ -199,9 +190,9 @@
} }
}, },
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "18.0.6", "version": "18.0.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.6.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.7.tgz",
"integrity": "sha512-ZMVmohV6CvAJtj++pZNyggluUt6hbRdQAxc2+Z635RL6/AG/ruXv5lHnybUFoxMPL/yrTL/tsF4paZu2l7RA6Q==", "integrity": "sha512-QEvMEF8ca3GNZJJnAbOgxpj5ULhBvnMcURp+XKrtvqFNPgjBvYoswQ0Jl2cO7JzCjxZjJhr9ZuIEhlrRxMft/Q==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"bin": { "bin": {
"dotenv": "dist/index.cjs" "dotenv": "dist/index.cjs"
@@ -288,15 +279,15 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "5.2.1", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-5.3.0.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "integrity": "sha512-qCqy1xSoaugxOD4IVHb1ZWdkvCF2W3aE2okKouWj8VwJ+ztskSiXoBnCSJqfKT+cVPJhuJqe9YLbY425+Zh00g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "^2.0.0", "accepts": "^2.0.0",
"body-parser": "^2.2.1", "body-parser": "^2.3.0",
"content-disposition": "^1.0.0", "content-disposition": "^2.0.1",
"content-type": "^1.0.5", "content-type": "^2.0.0",
"cookie": "^0.7.1", "cookie": "^0.7.1",
"cookie-signature": "^1.2.1", "cookie-signature": "^1.2.1",
"debug": "^4.4.0", "debug": "^4.4.0",
@@ -312,14 +303,14 @@
"on-finished": "^2.4.1", "on-finished": "^2.4.1",
"once": "^1.4.0", "once": "^1.4.0",
"parseurl": "^1.3.3", "parseurl": "^1.3.3",
"proxy-addr": "^2.0.7", "proxy-addr": "^2.0.8",
"qs": "^6.14.0", "qs": "^6.16.0",
"range-parser": "^1.2.1", "range-parser": "^1.2.1",
"router": "^2.2.0", "router": "^2.2.0",
"send": "^1.1.0", "send": "^1.1.0",
"serve-static": "^2.2.0", "serve-static": "^2.2.0",
"statuses": "^2.0.1", "statuses": "^2.0.1",
"type-is": "^2.0.1", "type-is": "^2.1.0",
"vary": "^1.1.2" "vary": "^1.1.2"
}, },
"engines": { "engines": {
@@ -589,19 +580,6 @@
"url": "https://opencollective.com/express" "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": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -905,19 +883,6 @@
"url": "https://opencollective.com/express" "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": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -928,9 +893,9 @@
} }
}, },
"node_modules/uuid": { "node_modules/uuid": {
"version": "14.0.2", "version": "14.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.3.tgz",
"integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", "integrity": "sha512-Sc5u1VVln93y1Xnz4R+CunOZc7R9LUcTmhj7Rc7Eg3HVcf7rVn2FOoa812fe0W8p3jD7xeoGSYbfqCGGH2B6xw==",
"funding": [ "funding": [
"https://github.com/sponsors/broofa", "https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan" "https://github.com/sponsors/ctavan"
@@ -11,8 +11,8 @@
"dependencies": { "dependencies": {
"chalk": "^6.0.1", "chalk": "^6.0.1",
"cors": "^2.8.6", "cors": "^2.8.6",
"dotenv": "^18.0.6", "dotenv": "^18.0.7",
"express": "^5.2.1", "express": "^5.3.0",
"uuid": "^14.0.2" "uuid": "^14.0.3"
} }
} }
@@ -10,7 +10,7 @@
<body> <body>
<main> <main>
<div class="container py-5"> <div class="container py-5">
<h1>Home</h1> <h1>Expres Rest API</h1>
<p>Server is running</p> <p>Server is running</p>
</div> </div>
</main> </main>
@@ -1,11 +1,14 @@
import express from 'express'; import express from 'express';
import color from 'chalk'; import color from 'chalk';
import dotenv from 'dotenv';
dotenv.config(); // Sensible Konfigurationsvariablen werden in einer .env Datei ausgelagert
// Models // Models
import ProductModel from './models/ProductModel.js'; import ProductModel from './models/ProductModel.js';
const PORT = 8000; const PORT = process.env.SERVER_PORT || 8000;
const HOST = '127.0.0.1'; const HOST = process.env.SERVER_HOST || '127.0.0.1';
const BASE_URL = `http://${HOST}:${PORT}`; const BASE_URL = `http://${HOST}:${PORT}`;
// lade Produkte // lade Produkte
@@ -52,32 +55,47 @@ app.get('/api/products', (req, res) => {
// B(R)EAD - read // B(R)EAD - read
app.get('/api/products/:id', (req, res) => { app.get('/api/products/:id', (req, res) => {
const { id } = req.params; const { id } = req.params;
const data = products.get(id); const product = products.get(id);
return res.send(data);
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) => { app.get('/', (req, res) => {
return res.send('Server is running!'); 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, () => { app.listen(PORT, HOST, () => {
console.log(color.magenta(`Server is running at: ${BASE_URL}`)); console.log(color.magenta(`Server is running at: ${BASE_URL}`));
console.log(color.yellow('To close: CTRL + C')); console.log(color.yellow('To close: CTRL + C'));