diff --git a/README.md b/README.md index 5241826b3..f76351a7a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ # Project Express API -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +In our first step into backend, the assigment was to create an API using Express. The API should have at least a couple of RESTful endpoints which return either an array of data or a single item. ## 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? +I created an API about dog breeds using Express.js and Node.js. The main challenge was getting the file paths right and figuring out how to filter the data by categories. I learned a lot about working with JSON data and API endpoints. +If I had more time, I would add more filtering options and create a simple frontend to display the data in a user-friendly way. ## 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. +https://project-express-api-y1pr.onrender.com/ + +GET "/" - Shows API documentation +GET "/dogs" - Returns all dogs (can be filtered by category using ?category=...) +GET "/dogs/:id" - Returns a specific dog by ID \ No newline at end of file diff --git a/data/dog-breeds.json b/data/dog-breeds.json new file mode 100644 index 000000000..c739b21b0 --- /dev/null +++ b/data/dog-breeds.json @@ -0,0 +1,242 @@ +[ + { + "id": 1, + "name": "German Shepherd", + "origin": "Germany", + "category": "Herding", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 2, + "name": "Labrador Retriever", + "origin": "Canada", + "category": "Sporting", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 3, + "name": "Poodle", + "origin": "Germany/France", + "category": "Non-Sporting", + "familyFriendly": "yes", + "size": "Various" + }, + { + "id": 4, + "name": "Golden Retriever", + "origin": "Scotland", + "category": "Sporting", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 5, + "name": "Bulldog", + "origin": "England", + "category": "Non-Sporting", + "familyFriendly": "yes", + "size": "Medium" + }, + { + "id": 6, + "name": "Rottweiler", + "origin": "Germany", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 7, + "name": "Beagle", + "origin": "England", + "category": "Hound", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 8, + "name": "Siberian Husky", + "origin": "Russia", + "category": "Working", + "familyFriendly": "yes", + "size": "Medium" + }, + { + "id": 9, + "name": "Chihuahua", + "origin": "Mexico", + "category": "Toy", + "familyFriendly": "no", + "size": "Small" + }, + { + "id": 10, + "name": "Great Dane", + "origin": "Germany", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 11, + "name": "Pug", + "origin": "China", + "category": "Toy", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 12, + "name": "Doberman Pinscher", + "origin": "Germany", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 13, + "name": "Yorkshire Terrier", + "origin": "England", + "category": "Toy", + "familyFriendly": "no", + "size": "Small" + }, + { + "id": 14, + "name": "Boxer", + "origin": "Germany", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 15, + "name": "Shih Tzu", + "origin": "Tibet", + "category": "Toy", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 16, + "name": "Australian Shepherd", + "origin": "United States", + "category": "Herding", + "familyFriendly": "yes", + "size": "Medium" + }, + { + "id": 17, + "name": "Border Collie", + "origin": "Scotland", + "category": "Herding", + "familyFriendly": "yes", + "size": "Medium" + }, + { + "id": 18, + "name": "Chow Chow", + "origin": "China", + "category": "Non-Sporting", + "familyFriendly": "no", + "size": "Medium" + }, + { + "id": 19, + "name": "Bernese Mountain Dog", + "origin": "Switzerland", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 20, + "name": "French Bulldog", + "origin": "France", + "category": "Non-Sporting", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 21, + "name": "Dachshund", + "origin": "Germany", + "category": "Hound", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 22, + "name": "Saint Bernard", + "origin": "Switzerland", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 23, + "name": "Corgi", + "origin": "Wales", + "category": "Herding", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 24, + "name": "Dalmatian", + "origin": "Croatia", + "category": "Non-Sporting", + "familyFriendly": "yes", + "size": "Medium" + }, + { + "id": 25, + "name": "Afghan Hound", + "origin": "Afghanistan", + "category": "Hound", + "familyFriendly": "no", + "size": "Large" + }, + { + "id": 26, + "name": "Alaskan Malamute", + "origin": "United States", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 27, + "name": "Bichon Frise", + "origin": "Spain", + "category": "Non-Sporting", + "familyFriendly": "yes", + "size": "Small" + }, + { + "id": 28, + "name": "Bull Terrier", + "origin": "England", + "category": "Terrier", + "familyFriendly": "yes", + "size": "Medium" + }, + { + "id": 29, + "name": "Greyhound", + "origin": "Egypt", + "category": "Hound", + "familyFriendly": "yes", + "size": "Large" + }, + { + "id": 30, + "name": "Newfoundland", + "origin": "Canada", + "category": "Working", + "familyFriendly": "yes", + "size": "Large" + } +] \ No newline at end of file diff --git a/package.json b/package.json index f93ddb524..b803e8db5 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,10 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", - "express": "^4.17.3", + "express": "^4.21.2", + "express-list-endpoints": "^7.1.1", "nodemon": "^3.0.1" - } + }, + "main": "server.js", + "keywords": [] } diff --git a/server.js b/server.js index b5fec6fe2..1ca482022 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,76 @@ -import express from "express"; -import cors from "cors"; +const express = require("express"); // Web application framework +const cors = require("cors"); // CORS is needed to allow requests from different domains +const listEndpoints = require('express-list-endpoints'); // Used to generate API documentation +const dogs = require("./data/dog-breeds.json"); // Import our dogs data from JSON file -// 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"; - -// 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 +// Sets up server port - uses environment variable if available, otherwise use 8080 const port = process.env.PORT || 8080; +// Initialize express application const app = express(); -// Add middlewares to enable cors and json body parsing -app.use(cors()); -app.use(express.json()); +// Middleware setup +app.use(cors()); // Enable CORS for all routes +app.use(express.json()); // Parse incoming JSON requests + +// Route for getting a single dog by ID +app.get("/dogs/:id", (req, res) => { + const id = req.params.id; // Get the ID from the URL parameter + console.log("Requested ID:", id, "Type:", typeof id); + + // Finds the dog with matching ID (converts string ID to number for comparison) + const dog = dogs.find(dog => { + return dog.id === parseInt(id); + }); + + // If no dog is found with that ID, return 404 error + if (!dog) { + res.status(404).json({ error: "Dog breed not found" }); + } else { + res.json(dog); // Return the found dog + } +}); + +// Route for getting all dogs, with optional filters +app.get("/dogs", (req, res) => { + const { category, size, origin, familyFriendly } = req.query; // Get all filters from query parameters + console.log("Query parameters:", req.query); + + let filteredDogs = [...dogs]; -// Start defining your routes here + if (category) { + filteredDogs = filteredDogs.filter(dog => + dog.category.toLowerCase() === category.toLowerCase() + ); + } + if (size) { + filteredDogs = filteredDogs.filter(dog => + dog.size.toLowerCase() === size.toLowerCase() + ); + } + if (origin) { + filteredDogs = filteredDogs.filter(dog => + dog.origin.toLowerCase() === origin.toLowerCase() + ); + } + if (familyFriendly) { + filteredDogs = filteredDogs.filter(dog => + dog.familyFriendly.toLowerCase() === familyFriendly.toLowerCase() + ); + } + + res.json(filteredDogs); +}); + +// Root route - returns API documentation app.get("/", (req, res) => { - res.send("Hello Technigo!"); + const endpoints = listEndpoints(app); // Generate list of all available endpoints + res.json({ + description: "Dog Breeds API - Access information about different dog breeds", + endpoints: endpoints // Shows all available API endpoints + }); }); // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); -}); +}); \ No newline at end of file