From 1c991735a464eef99c22b25fedb4a698f89dfd93 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Thu, 5 Dec 2024 20:42:29 +0100 Subject: [PATCH 01/27] Initial commit --- README.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5241826b3..2aff7c582 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,35 @@ # Project Express API -Replace this readme with your own information about your project. +This project marks the beginning of my backend journey with Express.js, featuring RESTful endpoints that return data from a hard-coded JSON file. -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +Array methods like .find(), .filter(), and .slice() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. + +## Requirements: +- The API should have at least 3 routes. + - The endpoint "/" should return documentation of your API using e.g. [Express List Endpoints](https://www.npmjs.com/package/express-list-endpoints) + - A minimum of one endpoint to return a **collection** of results (array of elements). + - A minimum of one endpoint to return a **single** result (single element). +- Your API should be RESTful. +- You should follow the guidelines on how to write clean code. ## The problem Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +## If I had more time - Stretch goals + +### Intermediate Stretch Goals +- On routes which return a single item, handle when the item doesn't exist and return some useful data in the response. + +- Accept filters via query parameters to filter the data you return from endpoints which return an array of data. + +- Create some empty/dummy endpoints which could contain more complex operations in the future. Find good names for them (think RESTful). + +### Advanced Stretch Goals +- Build a frontend which uses your API in some way to show the data in a nice way (use Vite to get up and running fast). + +- If your dataset is large, try implementing 'pages' using `.slice()` to return only a selection of results from the array. You could then use a query parameter to allow the client to ask for the next 'page'. + ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +Netlify link From 9922cf5b6a8b663b6a4b068cd1a849fbdb119c2b Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 19:57:20 +0100 Subject: [PATCH 02/27] Add a new json of elves. Import file to server.js and save port 1224. --- README.md | 20 +++ data/elves.json | 402 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 7 +- server.js | 5 +- 4 files changed, 430 insertions(+), 4 deletions(-) create mode 100644 data/elves.json diff --git a/README.md b/README.md index 2aff7c582..5caef412a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,26 @@ Array methods like .find(), .filter(), and .slice() are used to manipulate the d - Your API should be RESTful. - You should follow the guidelines on how to write clean code. +## Dependency Installation & Startup Development Server +This project uses npm (Node Package Manager) and Express.js to manage dependencies and run the development server. Follow these steps to get started: + 1. Install Project Dependencies + Run the following commands to install necessary packages and set up the development environment: + ```bash + npm install + npm run dev + npm run build + ``` + 2. If Express.js is not already installed, initialize your project and install it: + ```bash + npm init -y + npm install express + ``` + 3. Start your server + Launch the server: + ```bash + node server.js + ``` + ## The problem Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? diff --git a/data/elves.json b/data/elves.json new file mode 100644 index 000000000..99f90426a --- /dev/null +++ b/data/elves.json @@ -0,0 +1,402 @@ +[ + { + "elfID": 1, + "title": "Wish Programmer", + "Name": "Joyce", + "average_rating": 4.17, + "language_code": "en", + "text_reviews_count": 10 + }, + { + "elfID": 2, + "title": "Wish Programmer", + "Name": "Anna", + "average_rating": 4.08, + "language_code": "en", + "text_reviews_count": 14 + }, + { + "elfID": 3, + "title": "Wish Programmer", + "Name": "Erika", + "average_rating": 3.67, + "language_code": "en", + "text_reviews_count": 18 + }, + { + "elfID": 4, + "title": "Wish Programmer", + "Name": "Helene", + "average_rating": 4.7, + "language_code": "en", + "text_reviews_count": 16 + }, + { + "elfID": 5, + "title": "Wish Programmer", + "Name": "Fanny", + "average_rating": 4.47, + "language_code": "en", + "text_reviews_count": 20 + }, + { + "elfID": 6, + "title": "Wish Programmer", + "Name": "Johanna", + "average_rating": 4.57, + "language_code": "en", + "text_reviews_count": 19 + }, + { + "elfID": 7, + "title": "Wish Programmer", + "Name": "Gitte", + "average_rating": 3.78, + "languages": ["en", "de"], + "text_reviews_count": 12 + }, + { + "elfID": 8, + "title": "Wish Programmer", + "Name": "Gabriella", + "average_rating": 3.59, + "language_code": "en", + "text_reviews_count": 7 + }, + { + "elfID": 9, + "title": "Wish Programmer", + "Name": "Kelly", + "average_rating": 3.71, + "language_code": "en", + "text_reviews_count": 13 + }, + { + "elfID": 10, + "title": "Wish Programmer", + "Name": "Xing", + "average_rating": 4.38, + "language_code": "en", + "text_reviews_count": 6 + }, + { + "elfID": 11, + "title": "Wish Programmer", + "Name": "Zoe", + "average_rating": 4.4, + "language_code": "en", + "text_reviews_count": 10 + }, + { + "elfID": 12, + "title": "Wish Programmer", + "Name": "Liselotte", + "average_rating": 4.8, + "language_code": "en", + "text_reviews_count": 5 + }, + { + "elfID": 13, + "title": "Toy Designer", + "Name": "Buddy", + "average_rating": 3.94, + "language_code": "en", + "text_reviews_count": 22 + }, + { + "elfID": 14, + "title": "Gift Wrapper", + "Name": "Olof", + "average_rating": 4.73, + "language_code": "en", + "text_reviews_count": 24 + }, + { + "elfID": 15, + "title": "Cookie Tester", + "Name": "Karl", + "average_rating": 4.74, + "language_code": "en", + "text_reviews_count": 21 + }, + { + "elfID": 16, + "title": "Cookie Tester", + "Name": "Elsa", + "average_rating": 3.91, + "languages": ["en", "de"], + "text_reviews_count": 21 + }, + { + "elfID": 17, + "title": "Gift Wrapper", + "Name": "Olivia", + "average_rating": 4.94, + "language_code": "en", + "text_reviews_count": 10 + }, + { + "elfID": 18, + "title": "Sleigh Mechanic", + "Name": "Liam", + "average_rating": 4.12, + "language_code": "en", + "text_reviews_count": 20 + }, + { + "elfID": 19, + "title": "Toy Designer", + "Name": "Sophia", + "average_rating": 3.88, + "languages": ["en", "de"], + "text_reviews_count": 9 + }, + { + "elfID": 20, + "title": "Gift Wrapper", + "Name": "Zustand", + "average_rating": 3.94, + "languages": ["en", "de"], + "text_reviews_count": 17 + }, + { + "elfID": 21, + "title": "Gift Wrapper", + "Name": "Mia", + "average_rating": 4.13, + "language_code": "en", + "text_reviews_count": 29 + }, + { + "elfID": 22, + "title": "Cookie Tester", + "Name": "Ethan", + "average_rating": 4.04, + "language_code": "en", + "text_reviews_count": 27 + }, + { + "elfID": 23, + "title": "Cookie Tester", + "Name": "Emily", + "average_rating": 3.74, + "language_code": "en", + "text_reviews_count": 14 + }, + { + "elfID": 24, + "title": "Sleigh Mechanic", + "Name": "Logan", + "average_rating": 4.97, + "language_code": "en", + "text_reviews_count": 12 + }, + { + "elfID": 25, + "title": "Cookie Tester", + "Name": "Ella", + "average_rating": 4.82, + "language_code": "en", + "text_reviews_count": 18 + }, + { + "elfID": 26, + "title": "Sleigh Mechanic", + "Name": "Lucas", + "average_rating": 4.15, + "language_code": "en", + "text_reviews_count": 8 + }, + { + "elfID": 27, + "title": "Sleigh Mechanic", + "Name": "Ava", + "average_rating": 4.84, + "language_code": "en", + "text_reviews_count": 7 + }, + { + "elfID": 28, + "title": "Cookie Tester", + "Name": "Mason", + "average_rating": 4.95, + "language_code": "en", + "text_reviews_count": 24 + }, + { + "elfID": 29, + "title": "Cookie Tester", + "Name": "Isabella", + "average_rating": 4.42, + "language_code": "en", + "text_reviews_count": 26 + }, + { + "elfID": 30, + "title": "Toy Designer", + "Name": "Jacob", + "average_rating": 4.6, + "language_code": "en", + "text_reviews_count": 22 + }, + { + "elfID": 31, + "title": "Reindeer Trainer", + "Name": "Harper", + "average_rating": 4.56, + "language_code": "en", + "text_reviews_count": 6 + }, + { + "elfID": 32, + "title": "Sleigh Mechanic", + "Name": "Elijah", + "average_rating": 3.96, + "language_code": "en", + "text_reviews_count": 28 + }, + { + "elfID": 33, + "title": "Reindeer Trainer", + "Name": "Charlotte", + "average_rating": 4.78, + "language_code": "en", + "text_reviews_count": 6 + }, + { + "elfID": 34, + "title": "Sleigh Mechanic", + "Name": "Alexander", + "average_rating": 4.57, + "language_code": "en", + "text_reviews_count": 12 + }, + { + "elfID": 35, + "title": "Sleigh Mechanic", + "Name": "Amelia", + "average_rating": 4.9, + "language_code": "en", + "text_reviews_count": 18 + }, + { + "elfID": 36, + "title": "Gift Wrapper", + "Name": "James", + "average_rating": 4.87, + "language_code": "en", + "text_reviews_count": 22 + }, + { + "elfID": 37, + "title": "Toy Designer", + "Name": "Abigail", + "average_rating": 4.7, + "language_code": "en", + "text_reviews_count": 28 + }, + { + "elfID": 38, + "title": "Sleigh Mechanic", + "Name": "Benjamin", + "average_rating": 4.87, + "language_code": "en", + "text_reviews_count": 24 + }, + { + "elfID": 39, + "title": "Sleigh Mechanic", + "Name": "Sofia", + "average_rating": 4.98, + "language_code": "en", + "text_reviews_count": 10 + }, + { + "elfID": 40, + "title": "Sleigh Mechanic", + "Name": "William", + "average_rating": 4.03, + "language_code": "en", + "text_reviews_count": 18 + }, + { + "elfID": 41, + "title": "Reindeer Trainer", + "Name": "Emma", + "average_rating": 4.15, + "language_code": "en", + "text_reviews_count": 28 + }, + { + "elfID": 42, + "title": "Reindeer Trainer", + "Name": "Oliver", + "average_rating": 3.63, + "language_code": "en", + "text_reviews_count": 19 + }, + { + "elfID": 43, + "title": "Gift Wrapper", + "Name": "Aria", + "average_rating": 3.73, + "language_code": "en", + "text_reviews_count": 26 + }, + { + "elfID": 44, + "title": "Toy Designer", + "Name": "Henry", + "average_rating": 3.58, + "language_code": "en", + "text_reviews_count": 22 + }, + { + "elfID": 45, + "title": "Toy Designer", + "Name": "Scarlett", + "average_rating": 4.13, + "language_code": "en", + "text_reviews_count": 25 + }, + { + "elfID": 46, + "title": "Gift Wrapper", + "Name": "Samuel", + "average_rating": 4.47, + "language_code": "en", + "text_reviews_count": 10 + }, + { + "elfID": 47, + "title": "Reindeer Trainer", + "Name": "Hannah", + "average_rating": 3.52, + "language_code": "en", + "text_reviews_count": 26 + }, + { + "elfID": 48, + "title": "Cookie Tester", + "Name": "Jack", + "average_rating": 4.45, + "language_code": "en", + "text_reviews_count": 7 + }, + { + "elfID": 49, + "title": "Toy Designer", + "Name": "Grace", + "average_rating": 3.84, + "language_code": "en", + "text_reviews_count": 5 + }, + { + "elfID": 50, + "title": "Toy Designer", + "Name": "Levi", + "average_rating": 4.72, + "language_code": "en", + "text_reviews_count": 15 + } +] \ No newline at end of file diff --git a/package.json b/package.json index f93ddb524..109d20a3f 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "project-express-api", "version": "1.0.0", "description": "Starter project to get up and running with express quickly", + "type": "module", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" @@ -13,7 +14,9 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", - "express": "^4.17.3", + "express": "^4.21.1", "nodemon": "^3.0.1" - } + }, + "main": "server.js", + "keywords": [] } diff --git a/server.js b/server.js index b5fec6fe2..26f66f8f9 100644 --- a/server.js +++ b/server.js @@ -8,11 +8,12 @@ import cors from "cors"; // import goldenGlobesData from "./data/golden-globes.json"; // import netflixData from "./data/netflix-titles.json"; // import topMusicData from "./data/top-music.json"; +import elves from "./data/elves.json"; // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: -// PORT=9000 npm start -const port = process.env.PORT || 8080; +// PORT=1224 npm start +const port = process.env.PORT || 1224; // Hoho const app = express(); // Add middlewares to enable cors and json body parsing From 9ad54d589a2c1b90b770551c9cd45e886c2d5372 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 20:27:54 +0100 Subject: [PATCH 03/27] Install npm install express-list-endpoints and add to documentation --- README.md | 4 ++++ package.json | 5 +++-- server.js | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5caef412a..10afa5847 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ This project uses npm (Node Package Manager) and Express.js to manage dependenci ```bash node server.js ``` + 4. The package used to generate a list of all available API endpoints automatically (shown on the endpoint /). Install it with: + ```bash + npm install express-list-endpoints + ``` ## The problem diff --git a/package.json b/package.json index 109d20a3f..5ae78a79d 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,12 @@ "name": "project-express-api", "version": "1.0.0", "description": "Starter project to get up and running with express quickly", - "type": "module", + "type": "", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" }, - "author": "", + "author": "Johanna Eriksson", "license": "ISC", "dependencies": { "@babel/core": "^7.17.9", @@ -15,6 +15,7 @@ "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.21.1", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" }, "main": "server.js", diff --git a/server.js b/server.js index 26f66f8f9..abafbf2e9 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,7 @@ import cors from "cors"; // If you're using one of our datasets, uncomment the appropriate import below // to get started! // import avocadoSalesData from "./data/avocado-sales.json"; -// import booksData from "./data/books.json"; +//import booksData from "./data/books.json"; // import goldenGlobesData from "./data/golden-globes.json"; // import netflixData from "./data/netflix-titles.json"; // import topMusicData from "./data/top-music.json"; @@ -22,7 +22,7 @@ app.use(express.json()); // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!"); + res.send("Ho Ho!"); }); // Start the server From ddffbbea02dcb0006f16130ecbe796ff25cd32f8 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 20:30:38 +0100 Subject: [PATCH 04/27] Import import expressListEndpoints from 'express-list-endpoints' to the server.js file --- server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server.js b/server.js index abafbf2e9..c83912f9a 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ import express from "express"; import cors from "cors"; +import expressListEndpoints from 'express-list-endpoints'; // If you're using one of our datasets, uncomment the appropriate import below // to get started! From 0174836829f9c80cb12e2a1da24b75a63d31eaa3 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 20:46:31 +0100 Subject: [PATCH 05/27] Add first route that shows the API documentation --- package.json | 2 +- server.js | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 5ae78a79d..6d061754c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "project-express-api", "version": "1.0.0", "description": "Starter project to get up and running with express quickly", - "type": "", + "type": "commonjs", "scripts": { "start": "babel-node server.js", "dev": "nodemon server.js --exec babel-node" diff --git a/server.js b/server.js index c83912f9a..d9e51ddb9 100644 --- a/server.js +++ b/server.js @@ -1,19 +1,9 @@ import express from "express"; import cors from "cors"; import expressListEndpoints from 'express-list-endpoints'; - -// If you're using one of our datasets, uncomment the appropriate import below -// to get started! -// import avocadoSalesData from "./data/avocado-sales.json"; -//import booksData from "./data/books.json"; -// import goldenGlobesData from "./data/golden-globes.json"; -// import netflixData from "./data/netflix-titles.json"; -// import topMusicData from "./data/top-music.json"; import elves from "./data/elves.json"; -// Defines the port the app will run on. Defaults to 8080, but can be overridden -// when starting the server. Example command to overwrite PORT env variable value: -// PORT=1224 npm start +// Defines the port the app will run on. Defaults to 8080, but can be overridden when starting the server. Example command to overwrite PORT env variable value: PORT=1224 npm start const port = process.env.PORT || 1224; // Hoho const app = express(); @@ -21,9 +11,19 @@ const app = express(); app.use(cors()); app.use(express.json()); -// Start defining your routes here -app.get("/", (req, res) => { - res.send("Ho Ho!"); +// Documentation endpoint +app.get("/", (request, response) => { + const endpoints = expressListEndpoints(app); + response.json({ + message: "Welcome to the Elves API! Here are the available endpoints:", + endpoints: endpoints + }); +}); + +// Test endpoint +app.get("/test", (reqesst, response) => { + res.send("Testing testing!"); + console.log("Testing testing"); }); // Start the server From 46b695294a89504fd035d023b01a2a09449e0120 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 20:53:56 +0100 Subject: [PATCH 06/27] Fix typos --- server.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index d9e51ddb9..61e6a2b07 100644 --- a/server.js +++ b/server.js @@ -21,11 +21,23 @@ app.get("/", (request, response) => { }); // Test endpoint -app.get("/test", (reqesst, response) => { +app.get("/test", (request, response) => { res.send("Testing testing!"); console.log("Testing testing"); }); +// Endpoint to get all elves, with optional query filter +app.get("/elves", (req, res) => { + const title = req.query.title?.toLowerCase(); + console.log(title); + + const filteredElves = title + ? elves.filter((elf) => elf.title.toLowerCase() === title) + : elves; + + res.json(filteredElves); +}); + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From 0beb5c5acf32ef6726ff810bb4e40191424502c3 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 21:05:11 +0100 Subject: [PATCH 07/27] Add route to server.js that filters elves --- server.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/server.js b/server.js index 61e6a2b07..2b5d5e10b 100644 --- a/server.js +++ b/server.js @@ -22,20 +22,18 @@ app.get("/", (request, response) => { // Test endpoint app.get("/test", (request, response) => { - res.send("Testing testing!"); + response.send("Testing testing!"); console.log("Testing testing"); }); // Endpoint to get all elves, with optional query filter -app.get("/elves", (req, res) => { - const title = req.query.title?.toLowerCase(); +app.get("/elves", (request, response) => { + const title = request.query.title?.toLowerCase(); // console.log(title); - const filteredElves = title - ? elves.filter((elf) => elf.title.toLowerCase() === title) - : elves; + const filteredElves = elves.filter((event) => event.title.toLocaleLowerCase() === title); - res.json(filteredElves); + response.json(filteredElves); }); // Start the server From 1bac1f0ecf8345335411f1efa0b735e8489a802e Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 21:09:44 +0100 Subject: [PATCH 08/27] add rount for filter elves by id --- server.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server.js b/server.js index 2b5d5e10b..a3ae463a6 100644 --- a/server.js +++ b/server.js @@ -36,6 +36,19 @@ app.get("/elves", (request, response) => { response.json(filteredElves); }); +//Get a unique elf by ID + +app.get("/elves/:id", (request, response) => { + const id = request.params.id; + + const eld = elves.find((event) => event.elfID === +id); + if (elf) { + response.status(200).json(elf); + } else { + response.status(404).send("No eld found with that ID"); + } +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From 3078fb8472856fab15e21098fbe846c9368639a9 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 21:35:54 +0100 Subject: [PATCH 09/27] Change filtered elves since the previous one did not work --- server.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index a3ae463a6..500be513e 100644 --- a/server.js +++ b/server.js @@ -26,12 +26,17 @@ app.get("/test", (request, response) => { console.log("Testing testing"); }); -// Endpoint to get all elves, with optional query filter +// Endpoint to get all elves, with optional filter app.get("/elves", (request, response) => { - const title = request.query.title?.toLowerCase(); // - console.log(title); + const title = request.query.title?.toLowerCase(); + console.log(`Title filter: ${title}`); - const filteredElves = elves.filter((event) => event.title.toLocaleLowerCase() === title); + // Filter the elves based on the provided title + // If 'title' exists, return elves with titles that match, otherwise, return all elves + + const filteredElves = title + ? elves.filter((event) => event.title.toLowerCase() === title) + : elves; // Return all elves if no query parameter response.json(filteredElves); }); @@ -41,11 +46,11 @@ app.get("/elves", (request, response) => { app.get("/elves/:id", (request, response) => { const id = request.params.id; - const eld = elves.find((event) => event.elfID === +id); + const elf = elves.find((event) => event.elfID === +id); if (elf) { response.status(200).json(elf); } else { - response.status(404).send("No eld found with that ID"); + response.status(404).send("No elf found with that ID"); } }) From 68d146f0e2dc5fddd6048a8f4ad3a58013447918 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 22:14:53 +0100 Subject: [PATCH 10/27] Change elves filter from query param to path param --- server.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/server.js b/server.js index 500be513e..443eb468d 100644 --- a/server.js +++ b/server.js @@ -31,15 +31,14 @@ app.get("/elves", (request, response) => { const title = request.query.title?.toLowerCase(); console.log(`Title filter: ${title}`); - // Filter the elves based on the provided title + // Path parameter for getting elves based on the provided title // If 'title' exists, return elves with titles that match, otherwise, return all elves - const filteredElves = title - ? elves.filter((event) => event.title.toLowerCase() === title) - : elves; // Return all elves if no query parameter - - response.json(filteredElves); -}); + app.get("/elves/title/:title", (request, response) => { + const title = request.params.title.toLowerCase(); + const filteredElves = elves.filter((event) => event.title.toLowerCase() === title); + response.json(filteredElves); + }); //Get a unique elf by ID From 45b10fcc5b03243bd92eafc65b90d5b00dba30bf Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 22:17:26 +0100 Subject: [PATCH 11/27] Fix errors in code like missing curly brace --- server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index 443eb468d..967f9d716 100644 --- a/server.js +++ b/server.js @@ -28,8 +28,9 @@ app.get("/test", (request, response) => { // Endpoint to get all elves, with optional filter app.get("/elves", (request, response) => { - const title = request.query.title?.toLowerCase(); + const title = request.query.title?.toLowerCase(); console.log(`Title filter: ${title}`); +}); // Path parameter for getting elves based on the provided title // If 'title' exists, return elves with titles that match, otherwise, return all elves From d51a71a6f93e065c54a1cd85a6d20c3b11f11735 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 22:18:50 +0100 Subject: [PATCH 12/27] Change order of content in server.js --- server.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/server.js b/server.js index 967f9d716..20f23c621 100644 --- a/server.js +++ b/server.js @@ -20,26 +20,20 @@ app.get("/", (request, response) => { }); }); -// Test endpoint -app.get("/test", (request, response) => { - response.send("Testing testing!"); - console.log("Testing testing"); -}); - // Endpoint to get all elves, with optional filter app.get("/elves", (request, response) => { const title = request.query.title?.toLowerCase(); console.log(`Title filter: ${title}`); }); - // Path parameter for getting elves based on the provided title - // If 'title' exists, return elves with titles that match, otherwise, return all elves +// Path parameter for getting elves based on the provided title +// If 'title' exists, return elves with titles that match, otherwise, return all elves - app.get("/elves/title/:title", (request, response) => { - const title = request.params.title.toLowerCase(); - const filteredElves = elves.filter((event) => event.title.toLowerCase() === title); - response.json(filteredElves); - }); +app.get("/elves/title/:title", (request, response) => { + const title = request.params.title.toLowerCase(); + const filteredElves = elves.filter((event) => event.title.toLowerCase() === title); + response.json(filteredElves); +}); //Get a unique elf by ID @@ -54,6 +48,12 @@ app.get("/elves/:id", (request, response) => { } }) +// Test endpoint +app.get("/test", (request, response) => { + response.send("Testing testing!"); + console.log("Testing testing"); +}); + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From f5f6e89e46410d766a88e1ec9a9bef4be77caa60 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 22:31:58 +0100 Subject: [PATCH 13/27] change name on our titles to Backend Dasher :D --- data/elves.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/data/elves.json b/data/elves.json index 99f90426a..adc85f165 100644 --- a/data/elves.json +++ b/data/elves.json @@ -1,7 +1,7 @@ [ { "elfID": 1, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Joyce", "average_rating": 4.17, "language_code": "en", @@ -9,7 +9,7 @@ }, { "elfID": 2, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Anna", "average_rating": 4.08, "language_code": "en", @@ -17,7 +17,7 @@ }, { "elfID": 3, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Erika", "average_rating": 3.67, "language_code": "en", @@ -25,7 +25,7 @@ }, { "elfID": 4, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Helene", "average_rating": 4.7, "language_code": "en", @@ -33,7 +33,7 @@ }, { "elfID": 5, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Fanny", "average_rating": 4.47, "language_code": "en", @@ -41,7 +41,7 @@ }, { "elfID": 6, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Johanna", "average_rating": 4.57, "language_code": "en", @@ -49,7 +49,7 @@ }, { "elfID": 7, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Gitte", "average_rating": 3.78, "languages": ["en", "de"], @@ -57,7 +57,7 @@ }, { "elfID": 8, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Gabriella", "average_rating": 3.59, "language_code": "en", @@ -65,7 +65,7 @@ }, { "elfID": 9, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Kelly", "average_rating": 3.71, "language_code": "en", @@ -73,7 +73,7 @@ }, { "elfID": 10, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Xing", "average_rating": 4.38, "language_code": "en", @@ -81,7 +81,7 @@ }, { "elfID": 11, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Zoe", "average_rating": 4.4, "language_code": "en", @@ -89,7 +89,7 @@ }, { "elfID": 12, - "title": "Wish Programmer", + "title": "Backend Dasher", "Name": "Liselotte", "average_rating": 4.8, "language_code": "en", From 6213141ff852b2ae6d25afdfdcb8c31cf57db745 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 22:52:24 +0100 Subject: [PATCH 14/27] Add more info to readme --- README.md | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 10afa5847..59fb7d050 100644 --- a/README.md +++ b/README.md @@ -4,41 +4,50 @@ This project marks the beginning of my backend journey with Express.js, featurin Array methods like .find(), .filter(), and .slice() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. -## Requirements: -- The API should have at least 3 routes. - - The endpoint "/" should return documentation of your API using e.g. [Express List Endpoints](https://www.npmjs.com/package/express-list-endpoints) - - A minimum of one endpoint to return a **collection** of results (array of elements). - - A minimum of one endpoint to return a **single** result (single element). -- Your API should be RESTful. -- You should follow the guidelines on how to write clean code. +## Requirements: + 1. The API should have at least 3 routes. + This API has the following routes: + - /: Returns documentation of the API using express-list-endpoints.[Express List Endpoints](https://www.npmjs.com/package/express-list-endpoints). + 2. A minimum of one endpoint to return a **collection** of results (array of elements). + - /elves: Returns a collection of elves, with optional filtering by query parameter (?title=). + - /elves/title/:title: Returns elves by their title using a path parameter. + 3. A minimum of one endpoint to return a **single** result (single element). + - /elves/:id: Returns a single elf by ID. + 4. Your API should be RESTful. + - Routes (elves) are defined with endpoints such as /elves, /elves/:id, and /elves/title/:title. + - HTTP methods are used (GET). + - Responses are structured in JSON format. + 5. You should follow the guidelines on how to write clean code. + - Variable names are clear and descriptive (e.g. request, response, title). + - Each functionality is separated into its own endpoint. + - express.json() and cors() to handle JSON parsing and CORS issues ## Dependency Installation & Startup Development Server -This project uses npm (Node Package Manager) and Express.js to manage dependencies and run the development server. Follow these steps to get started: - 1. Install Project Dependencies - Run the following commands to install necessary packages and set up the development environment: +This project uses npm (Node Package Manager) and Express.js to manage dependencies and run the development server. Follow these steps to get started: + 1. Install Project Dependencies + Run the following commands to install necessary packages and set up the development environment: ```bash npm install npm run dev npm run build - ``` - 2. If Express.js is not already installed, initialize your project and install it: + ``` + 2. If Express.js is not already installed, initialize your project and install it: ```bash npm init -y npm install express - ``` - 3. Start your server + ``` + 3. Start your server Launch the server: ```bash node server.js - ``` - 4. The package used to generate a list of all available API endpoints automatically (shown on the endpoint /). Install it with: + ``` + 4. The package used to generate a list of all available API endpoints automatically (shown on the endpoint /). Install it with: ```bash npm install express-list-endpoints - ``` - -## The problem - -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? + ``` + +## The problem +This was my first backend project, and I found it a bit confusing to figure out what to install and why. I’m also not used to working without a UI, which made it tricky to test everything properly without clickable links or visual "feedback". ## If I had more time - Stretch goals @@ -56,4 +65,4 @@ Describe how you approached to problem, and what tools and techniques you used t ## View it live -Netlify link +[Check out the Elf's API here!](https://project-express-api-gyq9.onrender.com/) From 92ab7daba4dd7d956cd372604360f10413dc6944 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 23:06:54 +0100 Subject: [PATCH 15/27] Add description to server.js. Change one route (endpoint) to GET all elves --- README.md | 3 +++ server.js | 32 +++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 59fb7d050..4749dc970 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ Array methods like .find(), .filter(), and .slice() are used to manipulate the d 1. The API should have at least 3 routes. This API has the following routes: - /: Returns documentation of the API using express-list-endpoints.[Express List Endpoints](https://www.npmjs.com/package/express-list-endpoints). + - /elves: + - /elves/:id: + - /elves/title/:title: 2. A minimum of one endpoint to return a **collection** of results (array of elements). - /elves: Returns a collection of elves, with optional filtering by query parameter (?title=). - /elves/title/:title: Returns elves by their title using a path parameter. diff --git a/server.js b/server.js index 20f23c621..370bbfb70 100644 --- a/server.js +++ b/server.js @@ -16,14 +16,36 @@ app.get("/", (request, response) => { const endpoints = expressListEndpoints(app); response.json({ message: "Welcome to the Elves API! Here are the available endpoints:", - endpoints: endpoints + endpoints: endpoints, + description: { + "/elves/all": "Get all elves", + "/elves/titles": "Get all unique elf titles", + "/elves/title/:title": "Get elves by title", + "/elves/:id": "Get a specific elf by ID", + "/test": "Test endpoint" + } }); }); -// Endpoint to get all elves, with optional filter -app.get("/elves", (request, response) => { - const title = request.query.title?.toLowerCase(); - console.log(`Title filter: ${title}`); +// Endpoint to get all elves using a path parameter +app.get("/elves/all", (request, response) => { + + // Return all elves + response.json(elves); +}); + +// Endpoint to get all unique titles of elves +app.get("/elves/titles", (request, response) => { + // Extract titles and remove duplicates + const uniqueTitles = []; + elves.forEach((event) => { + if (!uniqueTitles.includes(event.title)) { + uniqueTitles.push(event.title); + } + }); + + // Return the unique titles + response.json(uniqueTitles); }); // Path parameter for getting elves based on the provided title From 29d6c43a35152986ff52939c9220a818d9e62940 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 23:10:48 +0100 Subject: [PATCH 16/27] Add more documentation to README --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4749dc970..ec59159d9 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,19 @@ Array methods like .find(), .filter(), and .slice() are used to manipulate the d 1. The API should have at least 3 routes. This API has the following routes: - /: Returns documentation of the API using express-list-endpoints.[Express List Endpoints](https://www.npmjs.com/package/express-list-endpoints). - - /elves: - - /elves/:id: - - /elves/title/:title: + - /elves/all - Get all elves + - /elves/:id: - Get a specific elf by ID + - /elves/titles - Get all unique elf titles + - /elves/title/:title: - Get elves by title + - /test - Test endpoint 2. A minimum of one endpoint to return a **collection** of results (array of elements). - - /elves: Returns a collection of elves, with optional filtering by query parameter (?title=). + - elves/all: Returns a collection of elves. + - /elves/titles: Returns all unique elf titles. - /elves/title/:title: Returns elves by their title using a path parameter. 3. A minimum of one endpoint to return a **single** result (single element). - /elves/:id: Returns a single elf by ID. 4. Your API should be RESTful. - - Routes (elves) are defined with endpoints such as /elves, /elves/:id, and /elves/title/:title. + - Routes (elves) are defined with endpoints such as /elves/:id, and /elves/title/:title. - HTTP methods are used (GET). - Responses are structured in JSON format. 5. You should follow the guidelines on how to write clean code. From 5856efa63e404e1d56fae970c3c9a39e93461fa3 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 23:15:02 +0100 Subject: [PATCH 17/27] Adjust the project description since I am not using slice(). --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ec59159d9..89c9d6f64 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ This project marks the beginning of my backend journey with Express.js, featuring RESTful endpoints that return data from a hard-coded JSON file. -Array methods like .find(), .filter(), and .slice() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. +Array methods like .find() and .filter() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. + +My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20dasher. ## Requirements: 1. The API should have at least 3 routes. From 9b79fc409baf883b64db04c0666bfa0b65e8c475 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 23:35:26 +0100 Subject: [PATCH 18/27] Removed and changed some data in the json file --- README.md | 2 +- data/elves.json | 176 +++++++++++++++++------------------------------- server.js | 6 +- 3 files changed, 68 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 89c9d6f64..6d0ea2577 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20da - /elves/all - Get all elves - /elves/:id: - Get a specific elf by ID - /elves/titles - Get all unique elf titles - - /elves/title/:title: - Get elves by title + - /elves/titles/:title: - Get elves by title - /test - Test endpoint 2. A minimum of one endpoint to return a **collection** of results (array of elements). - elves/all: Returns a collection of elves. diff --git a/data/elves.json b/data/elves.json index adc85f165..4ef35459a 100644 --- a/data/elves.json +++ b/data/elves.json @@ -3,400 +3,350 @@ "elfID": 1, "title": "Backend Dasher", "Name": "Joyce", - "average_rating": 4.17, - "language_code": "en", - "text_reviews_count": 10 + "language_code": ["en", "js"], + "reviews_count": 10 }, { "elfID": 2, "title": "Backend Dasher", "Name": "Anna", - "average_rating": 4.08, - "language_code": "en", - "text_reviews_count": 14 + "language_code": ["en", "js"], + "reviews_count": 14 }, { "elfID": 3, "title": "Backend Dasher", "Name": "Erika", - "average_rating": 3.67, - "language_code": "en", - "text_reviews_count": 18 + "language_code": ["en", "js"], + "reviews_count": 18 }, { "elfID": 4, "title": "Backend Dasher", "Name": "Helene", - "average_rating": 4.7, - "language_code": "en", - "text_reviews_count": 16 + "language_code": ["en", "js"], + "reviews_count": 16 }, { "elfID": 5, "title": "Backend Dasher", "Name": "Fanny", - "average_rating": 4.47, - "language_code": "en", - "text_reviews_count": 20 + "language_code": ["en", "js"], + "reviews_count": 20 }, { "elfID": 6, "title": "Backend Dasher", "Name": "Johanna", - "average_rating": 4.57, - "language_code": "en", - "text_reviews_count": 19 + "language_code": ["en", "js"], + "reviews_count": 19 }, { "elfID": 7, "title": "Backend Dasher", "Name": "Gitte", - "average_rating": 3.78, - "languages": ["en", "de"], - "text_reviews_count": 12 + "languages": ["en", "de", "js"], + "reviews_count": 12 }, { "elfID": 8, "title": "Backend Dasher", "Name": "Gabriella", - "average_rating": 3.59, - "language_code": "en", - "text_reviews_count": 7 + "language_code": ["en", "js"], + "reviews_count": 7 }, { "elfID": 9, "title": "Backend Dasher", "Name": "Kelly", - "average_rating": 3.71, - "language_code": "en", - "text_reviews_count": 13 + "language_code": ["en", "js"], + "reviews_count": 13 }, { "elfID": 10, "title": "Backend Dasher", "Name": "Xing", - "average_rating": 4.38, - "language_code": "en", - "text_reviews_count": 6 + "language_code": ["en", "js"], + "reviews_count": 6 }, { "elfID": 11, "title": "Backend Dasher", "Name": "Zoe", - "average_rating": 4.4, - "language_code": "en", - "text_reviews_count": 10 + "language_code": ["en", "js"], + "reviews_count": 10 }, { "elfID": 12, "title": "Backend Dasher", "Name": "Liselotte", - "average_rating": 4.8, - "language_code": "en", - "text_reviews_count": 5 + "language_code": ["en", "js"], + "reviews_count": 5 }, { "elfID": 13, "title": "Toy Designer", "Name": "Buddy", - "average_rating": 3.94, "language_code": "en", - "text_reviews_count": 22 + "reviews_count": 5 }, { "elfID": 14, "title": "Gift Wrapper", "Name": "Olof", - "average_rating": 4.73, "language_code": "en", - "text_reviews_count": 24 + "reviews_count": 24 }, { "elfID": 15, "title": "Cookie Tester", "Name": "Karl", - "average_rating": 4.74, "language_code": "en", - "text_reviews_count": 21 + "reviews_count": 21 }, { "elfID": 16, "title": "Cookie Tester", "Name": "Elsa", - "average_rating": 3.91, "languages": ["en", "de"], - "text_reviews_count": 21 + "reviews_count": 21 }, { "elfID": 17, "title": "Gift Wrapper", "Name": "Olivia", - "average_rating": 4.94, "language_code": "en", - "text_reviews_count": 10 + "reviews_count": 10 }, { "elfID": 18, "title": "Sleigh Mechanic", "Name": "Liam", - "average_rating": 4.12, "language_code": "en", - "text_reviews_count": 20 + "reviews_count": 20 }, { "elfID": 19, "title": "Toy Designer", "Name": "Sophia", - "average_rating": 3.88, "languages": ["en", "de"], - "text_reviews_count": 9 + "reviews_count": 9 }, { "elfID": 20, "title": "Gift Wrapper", "Name": "Zustand", - "average_rating": 3.94, - "languages": ["en", "de"], - "text_reviews_count": 17 + "languages": ["en", "de", "js"], + "reviews_count": 17 }, { "elfID": 21, "title": "Gift Wrapper", "Name": "Mia", - "average_rating": 4.13, "language_code": "en", - "text_reviews_count": 29 + "reviews_count": 29 }, { "elfID": 22, "title": "Cookie Tester", "Name": "Ethan", - "average_rating": 4.04, "language_code": "en", - "text_reviews_count": 27 + "reviews_count": 27 }, { "elfID": 23, "title": "Cookie Tester", "Name": "Emily", - "average_rating": 3.74, "language_code": "en", - "text_reviews_count": 14 + "reviews_count": 14 }, { "elfID": 24, "title": "Sleigh Mechanic", "Name": "Logan", - "average_rating": 4.97, "language_code": "en", - "text_reviews_count": 12 + "reviews_count": 12 }, { "elfID": 25, "title": "Cookie Tester", "Name": "Ella", - "average_rating": 4.82, "language_code": "en", - "text_reviews_count": 18 + "reviews_count": 18 }, { "elfID": 26, "title": "Sleigh Mechanic", "Name": "Lucas", - "average_rating": 4.15, "language_code": "en", - "text_reviews_count": 8 + "reviews_count": 8 }, { "elfID": 27, "title": "Sleigh Mechanic", "Name": "Ava", - "average_rating": 4.84, "language_code": "en", - "text_reviews_count": 7 + "reviews_count": 7 }, { "elfID": 28, "title": "Cookie Tester", "Name": "Mason", - "average_rating": 4.95, "language_code": "en", - "text_reviews_count": 24 + "reviews_count": 24 }, { "elfID": 29, "title": "Cookie Tester", "Name": "Isabella", - "average_rating": 4.42, "language_code": "en", - "text_reviews_count": 26 + "reviews_count": 26 }, { "elfID": 30, "title": "Toy Designer", "Name": "Jacob", - "average_rating": 4.6, "language_code": "en", - "text_reviews_count": 22 + "reviews_count": 22 }, { "elfID": 31, "title": "Reindeer Trainer", "Name": "Harper", - "average_rating": 4.56, "language_code": "en", - "text_reviews_count": 6 + "reviews_count": 6 }, { "elfID": 32, "title": "Sleigh Mechanic", "Name": "Elijah", - "average_rating": 3.96, "language_code": "en", - "text_reviews_count": 28 + "reviews_count": 28 }, { "elfID": 33, "title": "Reindeer Trainer", "Name": "Charlotte", - "average_rating": 4.78, "language_code": "en", - "text_reviews_count": 6 + "reviews_count": 6 }, { "elfID": 34, "title": "Sleigh Mechanic", "Name": "Alexander", - "average_rating": 4.57, "language_code": "en", - "text_reviews_count": 12 + "reviews_count": 12 }, { "elfID": 35, "title": "Sleigh Mechanic", "Name": "Amelia", - "average_rating": 4.9, "language_code": "en", - "text_reviews_count": 18 + "reviews_count": 18 }, { "elfID": 36, "title": "Gift Wrapper", "Name": "James", - "average_rating": 4.87, "language_code": "en", - "text_reviews_count": 22 + "reviews_count": 22 }, { "elfID": 37, "title": "Toy Designer", "Name": "Abigail", - "average_rating": 4.7, "language_code": "en", - "text_reviews_count": 28 + "reviews_count": 28 }, { "elfID": 38, "title": "Sleigh Mechanic", "Name": "Benjamin", - "average_rating": 4.87, "language_code": "en", - "text_reviews_count": 24 + "reviews_count": 24 }, { "elfID": 39, "title": "Sleigh Mechanic", "Name": "Sofia", - "average_rating": 4.98, "language_code": "en", - "text_reviews_count": 10 + "reviews_count": 10 }, { "elfID": 40, "title": "Sleigh Mechanic", "Name": "William", - "average_rating": 4.03, "language_code": "en", - "text_reviews_count": 18 + "reviews_count": 18 }, { "elfID": 41, "title": "Reindeer Trainer", "Name": "Emma", - "average_rating": 4.15, "language_code": "en", - "text_reviews_count": 28 + "reviews_count": 28 }, { "elfID": 42, "title": "Reindeer Trainer", "Name": "Oliver", - "average_rating": 3.63, "language_code": "en", - "text_reviews_count": 19 + "reviews_count": 19 }, { "elfID": 43, "title": "Gift Wrapper", "Name": "Aria", - "average_rating": 3.73, "language_code": "en", - "text_reviews_count": 26 + "reviews_count": 26 }, { "elfID": 44, "title": "Toy Designer", "Name": "Henry", - "average_rating": 3.58, "language_code": "en", - "text_reviews_count": 22 + "reviews_count": 22 }, { "elfID": 45, "title": "Toy Designer", "Name": "Scarlett", - "average_rating": 4.13, "language_code": "en", - "text_reviews_count": 25 + "reviews_count": 25 }, { "elfID": 46, "title": "Gift Wrapper", "Name": "Samuel", - "average_rating": 4.47, "language_code": "en", - "text_reviews_count": 10 + "reviews_count": 10 }, { "elfID": 47, "title": "Reindeer Trainer", "Name": "Hannah", - "average_rating": 3.52, "language_code": "en", - "text_reviews_count": 26 + "reviews_count": 26 }, { "elfID": 48, "title": "Cookie Tester", "Name": "Jack", - "average_rating": 4.45, "language_code": "en", - "text_reviews_count": 7 + "reviews_count": 7 }, { "elfID": 49, "title": "Toy Designer", "Name": "Grace", - "average_rating": 3.84, "language_code": "en", - "text_reviews_count": 5 + "reviews_count": 5 }, { "elfID": 50, "title": "Toy Designer", "Name": "Levi", - "average_rating": 4.72, "language_code": "en", - "text_reviews_count": 15 + "reviews_count": 15 } ] \ No newline at end of file diff --git a/server.js b/server.js index 370bbfb70..0f9dd0686 100644 --- a/server.js +++ b/server.js @@ -20,7 +20,7 @@ app.get("/", (request, response) => { description: { "/elves/all": "Get all elves", "/elves/titles": "Get all unique elf titles", - "/elves/title/:title": "Get elves by title", + "/elves/titles/:title": "Get elves by title", "/elves/:id": "Get a specific elf by ID", "/test": "Test endpoint" } @@ -51,9 +51,11 @@ app.get("/elves/titles", (request, response) => { // Path parameter for getting elves based on the provided title // If 'title' exists, return elves with titles that match, otherwise, return all elves -app.get("/elves/title/:title", (request, response) => { +app.get("/elves/titles/:title", (request, response) => { const title = request.params.title.toLowerCase(); const filteredElves = elves.filter((event) => event.title.toLowerCase() === title); + + // Return elves with titles that match response.json(filteredElves); }); From 6f4757ad72c23359a08fdb6f1d1eb145ab5d5151 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 23:43:40 +0100 Subject: [PATCH 19/27] Change order in the documentation endpoint to show description before endpoints --- server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 0f9dd0686..91f2ea798 100644 --- a/server.js +++ b/server.js @@ -16,13 +16,13 @@ app.get("/", (request, response) => { const endpoints = expressListEndpoints(app); response.json({ message: "Welcome to the Elves API! Here are the available endpoints:", - endpoints: endpoints, description: { "/elves/all": "Get all elves", "/elves/titles": "Get all unique elf titles", "/elves/titles/:title": "Get elves by title", "/elves/:id": "Get a specific elf by ID", - "/test": "Test endpoint" + "/test": "Test endpoint", + endpoints: endpoints } }); }); From 477520cd09b2f8f8025979f7293c1f5f3e6bc994 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sat, 7 Dec 2024 23:50:53 +0100 Subject: [PATCH 20/27] Fix nesting --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 91f2ea798..4f6d86028 100644 --- a/server.js +++ b/server.js @@ -22,7 +22,7 @@ app.get("/", (request, response) => { "/elves/titles/:title": "Get elves by title", "/elves/:id": "Get a specific elf by ID", "/test": "Test endpoint", - endpoints: endpoints + endpoints: endpoints } }); }); From fa991bf80ff52003c20a4db4e4f33583a5e593e1 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 20:04:35 +0100 Subject: [PATCH 21/27] Add route /elves/top-twelves to use .slice(), that GET the top 12 elves --- README.md | 16 ++++++++-------- server.js | 21 ++++++++------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 6d0ea2577..b1058e63a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This project marks the beginning of my backend journey with Express.js, featuring RESTful endpoints that return data from a hard-coded JSON file. -Array methods like .find() and .filter() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. +Array methods like .find(), .filter(), and .slice() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20dasher. @@ -11,18 +11,18 @@ My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20da This API has the following routes: - /: Returns documentation of the API using express-list-endpoints.[Express List Endpoints](https://www.npmjs.com/package/express-list-endpoints). - /elves/all - Get all elves - - /elves/:id: - Get a specific elf by ID - - /elves/titles - Get all unique elf titles - - /elves/titles/:title: - Get elves by title + - /elves/top-twelves - Get top TwElves using .slice() + - /elves/:id: - Get a specific elf by ID using .find() + - /elves/titles/:title: - Get elves by title using .filter() - /test - Test endpoint 2. A minimum of one endpoint to return a **collection** of results (array of elements). - - elves/all: Returns a collection of elves. - - /elves/titles: Returns all unique elf titles. - - /elves/title/:title: Returns elves by their title using a path parameter. + - elves/all: Returns a collection of elves. + - /elves/top-twelves - Get top TwElves. + - /elves/titles/:title: Returns elves by their title. 3. A minimum of one endpoint to return a **single** result (single element). - /elves/:id: Returns a single elf by ID. 4. Your API should be RESTful. - - Routes (elves) are defined with endpoints such as /elves/:id, and /elves/title/:title. + - Routes (elves) are defined with endpoints such as /elves/:id, and /elves/titles/:title. - HTTP methods are used (GET). - Responses are structured in JSON format. 5. You should follow the guidelines on how to write clean code. diff --git a/server.js b/server.js index 4f6d86028..cb33baa6f 100644 --- a/server.js +++ b/server.js @@ -18,7 +18,7 @@ app.get("/", (request, response) => { message: "Welcome to the Elves API! Here are the available endpoints:", description: { "/elves/all": "Get all elves", - "/elves/titles": "Get all unique elf titles", + "/elves/top-twelves": "Get the top twelves", "/elves/titles/:title": "Get elves by title", "/elves/:id": "Get a specific elf by ID", "/test": "Test endpoint", @@ -34,22 +34,17 @@ app.get("/elves/all", (request, response) => { response.json(elves); }); -// Endpoint to get all unique titles of elves -app.get("/elves/titles", (request, response) => { - // Extract titles and remove duplicates - const uniqueTitles = []; - elves.forEach((event) => { - if (!uniqueTitles.includes(event.title)) { - uniqueTitles.push(event.title); - } - }); +// Endpoint to get the top 12 elves, the "TwElves" + +app.get("/elves/top-twelves", (request, response) => { + //Use slice to get the first 12 elves + const topElves = elves.slice(0, 12); - // Return the unique titles - response.json(uniqueTitles); + // Return top 12 elves + response.json(topElves); }); // Path parameter for getting elves based on the provided title -// If 'title' exists, return elves with titles that match, otherwise, return all elves app.get("/elves/titles/:title", (request, response) => { const title = request.params.title.toLowerCase(); From c217dbefc85b87e85334315bdee07b77b25932be Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 20:25:29 +0100 Subject: [PATCH 22/27] Update documentation --- README.md | 2 +- server.js | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b1058e63a..776f13aac 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This project marks the beginning of my backend journey with Express.js, featurin Array methods like .find(), .filter(), and .slice() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. -My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20dasher. +My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20dasher or /elves/top-twelves ## Requirements: 1. The API should have at least 3 routes. diff --git a/server.js b/server.js index cb33baa6f..ba913c35c 100644 --- a/server.js +++ b/server.js @@ -27,25 +27,32 @@ app.get("/", (request, response) => { }); }); -// Endpoint to get all elves using a path parameter +/** + * Endpoint for getting all elves. + * This endpoint returns the complete list of elves from the elves.json. + */ + app.get("/elves/all", (request, response) => { // Return all elves response.json(elves); }); -// Endpoint to get the top 12 elves, the "TwElves" - +/** + * Endpoint to get the top 12 elves, the "TwElves" + * This endpoint uses .slice() to return the first 12 elves from the elves.json. + */ app.get("/elves/top-twelves", (request, response) => { - //Use slice to get the first 12 elves const topElves = elves.slice(0, 12); // Return top 12 elves response.json(topElves); }); -// Path parameter for getting elves based on the provided title - +/** + * Endpoint for getting elves based on the provided title. + * This endpoint uses .filter() to return the elves with a matching title + */ app.get("/elves/titles/:title", (request, response) => { const title = request.params.title.toLowerCase(); const filteredElves = elves.filter((event) => event.title.toLowerCase() === title); @@ -55,6 +62,12 @@ app.get("/elves/titles/:title", (request, response) => { }); //Get a unique elf by ID +/** + * Endpoint for getting elves based on a unique ID. + * This endpoint uses .find() to search for the elf in the elves.json. + * If an elf with the given ID exists, it returns the elf's data with a 200 status. + * If no elf is found, it returns with a 404 status and the message: "404 - No elf found with that ID". + */ app.get("/elves/:id", (request, response) => { const id = request.params.id; @@ -63,17 +76,23 @@ app.get("/elves/:id", (request, response) => { if (elf) { response.status(200).json(elf); } else { - response.status(404).send("No elf found with that ID"); + response.status(404).send("404 - No elf found with that ID"); } }) -// Test endpoint +/** + * Endpoint for testing the server. + * This endpoint confirms that the server is running and responds with "Testing testing!" + */ app.get("/test", (request, response) => { response.send("Testing testing!"); console.log("Testing testing"); }); -// Start the server +/** + * Start the server. + * The server listens on the specified port and logs the URL to the console. + */ app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); }); From 53368c5e7dfe1061773f39b6264059a145345988 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 20:36:30 +0100 Subject: [PATCH 23/27] Change message for testing the server --- README.md | 2 +- server.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 776f13aac..326f4c5b1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This project marks the beginning of my backend journey with Express.js, featurin Array methods like .find(), .filter(), and .slice() are used to manipulate the data. While pre-made datasets are available, I chose to create my own for a personalized touch. -My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20dasher or /elves/top-twelves +My crew of elves, the Backend Dashers, can be found at /elves/title/backend%20dasher or at /elves/top-twelves ## Requirements: 1. The API should have at least 3 routes. diff --git a/server.js b/server.js index ba913c35c..9fdc7265e 100644 --- a/server.js +++ b/server.js @@ -82,11 +82,11 @@ app.get("/elves/:id", (request, response) => { /** * Endpoint for testing the server. - * This endpoint confirms that the server is running and responds with "Testing testing!" + * This endpoint confirms that the server is running and responds with "Jingle bells, the server tells, it's up and running well!" */ app.get("/test", (request, response) => { - response.send("Testing testing!"); - console.log("Testing testing"); + response.send("Jingle bells, the server tells, it's up and running well!"); + console.log("Jingle bells, the server tells, it's up and running well!"); }); /** From 625da6e13dc463302ced46aac37235dba1a5dd5d Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 22:20:35 +0100 Subject: [PATCH 24/27] Change name from event to elf to make code easier to understadn --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 9fdc7265e..ac2318d5b 100644 --- a/server.js +++ b/server.js @@ -55,7 +55,7 @@ app.get("/elves/top-twelves", (request, response) => { */ app.get("/elves/titles/:title", (request, response) => { const title = request.params.title.toLowerCase(); - const filteredElves = elves.filter((event) => event.title.toLowerCase() === title); + const filteredElves = elves.filter((elf) => elf.title.toLowerCase() === title); // Return elves with titles that match response.json(filteredElves); From e2ae9f60155c70676c4a917fc77d532fdece3fcf Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 22:23:35 +0100 Subject: [PATCH 25/27] Change event to record to make the code more readable --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index ac2318d5b..68d631877 100644 --- a/server.js +++ b/server.js @@ -72,7 +72,7 @@ app.get("/elves/titles/:title", (request, response) => { app.get("/elves/:id", (request, response) => { const id = request.params.id; - const elf = elves.find((event) => event.elfID === +id); + const elf = elves.find((record) => record.elfID === +id); if (elf) { response.status(200).json(elf); } else { From 51808dedb44fa7768893a2126774ef1d13d950ff Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 22:38:23 +0100 Subject: [PATCH 26/27] Save any unsaved changes --- server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server.js b/server.js index 68d631877..dafbc358f 100644 --- a/server.js +++ b/server.js @@ -45,6 +45,8 @@ app.get("/elves/all", (request, response) => { app.get("/elves/top-twelves", (request, response) => { const topElves = elves.slice(0, 12); + console.log(elves.length); + // Return top 12 elves response.json(topElves); }); From e4ce77693365ba010c9e2d97b77b34b2a8451a53 Mon Sep 17 00:00:00 2001 From: Johanna Eriksson Date: Sun, 8 Dec 2024 23:11:31 +0100 Subject: [PATCH 27/27] Save any unsaved changes --- server.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/server.js b/server.js index dafbc358f..3a5918055 100644 --- a/server.js +++ b/server.js @@ -45,8 +45,6 @@ app.get("/elves/all", (request, response) => { app.get("/elves/top-twelves", (request, response) => { const topElves = elves.slice(0, 12); - console.log(elves.length); - // Return top 12 elves response.json(topElves); }); @@ -63,7 +61,6 @@ app.get("/elves/titles/:title", (request, response) => { response.json(filteredElves); }); -//Get a unique elf by ID /** * Endpoint for getting elves based on a unique ID. * This endpoint uses .find() to search for the elf in the elves.json.