feat: day 29

This commit is contained in:
Philippe Torrel
2026-07-23 14:00:55 +02:00
parent ad296423bc
commit 702443e90e
18 changed files with 1248 additions and 11 deletions

48
webseite/backend/api.rest Normal file
View File

@@ -0,0 +1,48 @@
# BROWSE Products
GET http://127.0.0.1:8000/api/products
###
# READ Product
GET http://127.0.0.1:8000/api/products/c38913d4-9524-461f-85d2-525241166e8e
###
# ADD Product
POST http://127.0.0.1:8000/api/products
Content-Type: application/json
{
"name": "Testproduct",
"price": 9.99
}
###
# UPDATE Product
PUT http://127.0.0.1:8000/api/products
Content-Type: application/json
{
"_id": "940c316b-518c-4a18-b1f6-328e010eef4d",
"name": "Testproduct Updated",
"price": 123.22
}
###
# DELETE Product
DELETE http://127.0.0.1:8000/api/products/940c316b-518c-4a18-b1f6-328e010eef4d
Content-Type: application/json

View File

@@ -22,5 +22,17 @@
"position": 4,
"name": "16-Bit Legendary Hero Heat-Change Mug",
"price": 12.99
},
{
"_id": "3b3352c1-789d-4b4f-8a93-f05f44ece5a5",
"position": 5,
"name": "32-Bit Legendary Hero Heat-Change Mug",
"price": 18.99
},
{
"_id": "5af39d33-cbcd-42c7-a160-50084faa91ba",
"position": 6,
"name": "64-Bit Legendary Hero Heat-Change Mug",
"price": 21.99
}
]
]

View File

@@ -1,4 +1,5 @@
import fs from 'node:fs';
import { v4 as id } from 'uuid';
// Factoryfunction
const ProductModel = () => {
@@ -13,6 +14,14 @@ const ProductModel = () => {
}
};
const save = () => {
try {
fs.writeFileSync('./data/products.json', JSON.stringify(products, null, 2), 'utf-8');
} catch (error) {
console.log('Something went wrong:', error);
}
};
const getAll = () => {
return products;
};
@@ -28,11 +37,66 @@ const ProductModel = () => {
return product;
};
const add = (product) => {
const { name, price } = product;
if (!hasAllProps(product)) return false;
products.push({
_id: id(),
name,
price: Number(price.toFixed(2)),
position: products.length + 1,
});
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;
};
/**
* hasAllProps - Überprüfung ob Product "name" und "price"
* @return boolean
**/
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: load
load,
save,
add,
getAll,
get,
update,
delete: remove,
};
};

View File

@@ -12,7 +12,8 @@
"chalk": "^5.6.2",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"express": "^5.2.1"
"express": "^5.2.1",
"uuid": "^14.0.1"
}
},
"node_modules/accepts": {
@@ -896,6 +897,19 @@
"node": ">= 0.8"
}
},
"node_modules/uuid": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz",
"integrity": "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist-node/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View File

@@ -13,6 +13,7 @@
"chalk": "^5.6.2",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"express": "^5.2.1"
"express": "^5.2.1",
"uuid": "^14.0.1"
}
}

View File

@@ -22,6 +22,7 @@ products.load();
// Middleware
app.use(cors(corsOptions)); // Fängt alle HTTP-Requests vor den Routenabfragen ab.
app.use(express.json()); // HTTP-Request Body wird als JSON Objekt erwartet und geparsed wird.
// Routes
app.get('/', (req, res) => {
@@ -43,11 +44,78 @@ app.get('/persons', (req, res) => {
res.send(persons);
});
// REST API ======
// Representational State Transfer (abgekürzt REST)
// GET - Daten Holen
// POST - Daten hinzufügen
// PUT/PATCH - Daten aktualisieren / Einen Datensatz aktualisieren
// DELETE - Daten löschen
// HTTP - Methode - POST
// (C)RUD - create - neues Produkt erstellen
// BRE(A)D - add
app.post('/api/products', (req, res) => {
const product = req.body;
if (!products.add(product)) {
return res.status(400).send({ msg: 'Could not add product', status: 400, success: false });
}
res.send({ msg: 'Product added', status: 200, success: true, data: product });
});
// HTTP - Methode - GET
// C(R)UD - read
// (B)READ - browse
app.get('/api/products', (req, res) => {
const data = products.getAll();
res.send(data);
});
// HTTP - Methode - GET
// C(R)UD - read
// B(R)EAD - read
app.get('/api/products/:id', (req, res) => {
const id = req.params.id; // routenparameter :id wird als Eigenschaft in params-Objekt abgelegt
const product = products.get(id);
if (!product) {
return res.status(400).send({ msg: 'Could not get product', status: 400, success: false });
}
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 });
}
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.id;
if (!products.delete(id)) {
return res.status(400).send({ msg: 'Could not delete product', status: 400, success: false });
}
res.send({ msg: 'Product deleted', status: 200, success: true, data: id });
});
// =========
app.listen(PORT, HOST, () => {
console.log(color.magenta(`🚀 Server is running at: ${BASE_URL}`));
console.log(color.yellow('CTRL + C to close.'));