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 { 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,
};
};
@@ -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"
@@ -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"
}
}
@@ -10,7 +10,7 @@
<body>
<main>
<div class="container py-5">
<h1>Home</h1>
<h1>Expres Rest API</h1>
<p>Server is running</p>
</div>
</main>
@@ -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'));