From c96f77f72d6a0237a8c1644ae9b761253d0732fa Mon Sep 17 00:00:00 2001 From: Gitte Beckmann Date: Wed, 11 Dec 2024 18:42:44 +0100 Subject: [PATCH 1/5] - added a first endpoint "books" and connected to MongoDB using Mongoose --- server.js | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/server.js b/server.js index 647e7b144..ae85be126 100644 --- a/server.js +++ b/server.js @@ -1,18 +1,42 @@ import express from "express"; +import bodyParser from "body-parser"; import cors from "cors"; import mongoose from "mongoose"; +import booksData from "./data/books.json"; -// 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"; +const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1:27017/books"; +mongoose.connect(mongoUrl) -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; -mongoose.connect(mongoUrl); -mongoose.Promise = Promise; + .then(() => { + console.log('MongoDB successfully connected!') + }) + .catch((error) => { + console.error('Error to connect with MongoDB', error) + }) + +const Book = mongoose.model('Book', { + title: String +}) + +if (process.env.RESET_DB) { + const seedDatabase = async () => { + try { + await Book.deleteMany({}); + + const savePromises = booksData.map((bookData) => { + const book = new Book(bookData); + return book.save(); + }); + + await Promise.all(savePromises); + console.log('Database seeded with books data'); + } catch (error) { + console.error('Error seeding database:', error); + } + }; + + seedDatabase(); +} // 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: @@ -29,6 +53,17 @@ app.get("/", (req, res) => { res.send("Hello Technigo!"); }); +// Route to get books +app.get('/books', async (req, res) => { +try { + const books = await Book.find() + res.json(books) +}catch (error) { + console.error('Error retrieving books', error); + res.status(500).send('Server error'); +} +}) + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From c6b6ec22f1ea6c18229b381f088a53ae389f8cee Mon Sep 17 00:00:00 2001 From: Gitte Beckmann Date: Fri, 13 Dec 2024 11:13:42 +0100 Subject: [PATCH 2/5] added mongo atlas and seeded data in it --- package.json | 4 ++ server.js | 113 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 90 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 6830a48aa..8eee0dfe3 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,12 @@ "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", + "dotenv": "^16.4.7", "express": "^4.17.3", "mongoose": "^8.0.0", "nodemon": "^3.0.1" + }, + "devDependencies": { + "@types/node": "^22.10.2" } } diff --git a/server.js b/server.js index ae85be126..f1e0f2675 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,16 @@ import express from "express"; -import bodyParser from "body-parser"; import cors from "cors"; import mongoose from "mongoose"; import booksData from "./data/books.json"; +import dotenv from "dotenv"; -const mongoUrl = process.env.MONGO_URL || "mongodb://127.0.0.1:27017/books"; -mongoose.connect(mongoUrl) +dotenv.config() + +// Connecting to MongoDB +// const mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/books' +const mongoURI = process.env.MONGODB_URI + +mongoose.connect(mongoURI) .then(() => { console.log('MongoDB successfully connected!') @@ -14,29 +19,14 @@ mongoose.connect(mongoUrl) console.error('Error to connect with MongoDB', error) }) -const Book = mongoose.model('Book', { - title: String -}) - -if (process.env.RESET_DB) { - const seedDatabase = async () => { - try { - await Book.deleteMany({}); - - const savePromises = booksData.map((bookData) => { - const book = new Book(bookData); - return book.save(); - }); - - await Promise.all(savePromises); - console.log('Database seeded with books data'); - } catch (error) { - console.error('Error seeding database:', error); - } - }; - - seedDatabase(); -} +// Setting a book schema and model +const Book = mongoose.model('Book', new mongoose.Schema({ + title: String, + authors: String, + isbn: Number, + language_code: String, + num_pages: Number +})); // 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: @@ -44,6 +34,16 @@ if (process.env.RESET_DB) { const port = process.env.PORT || 8080; const app = express(); +if (process.env.RESET_DB) { + const seedDatabase = async () => { + await Book.deleteMany({}); + booksData.forEach(book => { + new Book(book).save() + }) + } + seedDatabase() +} + // Add middlewares to enable cors and json body parsing app.use(cors()); app.use(express.json()); @@ -62,7 +62,66 @@ try { console.error('Error retrieving books', error); res.status(500).send('Server error'); } -}) +}); + +// Route to get books by author +app.get('/books/author/:author', async (req, res) => { + const { author } = req.params; // Get the author from the URL parameter + try { + const books = await Book.find({ authors: new RegExp(author, 'i') }); // Find books by author (case insensitive) + if (books.length === 0) { + return res.status(404).send('No books found for this author'); + } + res.json(books); + } catch (error) { + console.error('Error retrieving books by author', error); + res.status(500).send('Server error'); + } +}); + +app.get('/books/title/:title', async (req, res) => { + const { title } = req.params; // Get the title from the URL parameter + try { + const book = await Book.findOne({ title: title }); // Query the book by title + if (!book) { + return res.status(404).send('Book not found'); // If no book is found, return 404 + } + res.json(book); // Send the book as a JSON response + } catch (error) { + console.error('Error retrieving book', error); + res.status(500).send('Server error'); + } +}); + +// Route to get books by isbn +app.get('/books/isbn/:isbn', async (req, res) => { + const { isbn } = req.params; + try { + const book = await Book.findOne({ isbn: isbn }); + if (!book) { + return res.status(404).send('Book not found'); + } + res.json(book); + } catch (error) { + console.error('Error retrieving book by ISBN', error); + res.status(500).send('Server error'); + } +}); + +// Route to get books by language +app.get('/books/language/:language', async (req, res) => { + const { language } = req.params; + try { + const books = await Book.find({ language_code: language }); + if (books.length === 0) { + return res.status(404).send('No books found for this language'); + } + res.json(books); + } catch (error) { + console.error('Error retrieving books by language', error); + res.status(500).send('Server error'); + } +}); // Start the server app.listen(port, () => { From 1c2e9f80e2df1203845d9ecf636ccf1e628641a2 Mon Sep 17 00:00:00 2001 From: Gitte Beckmann Date: Fri, 13 Dec 2024 11:31:49 +0100 Subject: [PATCH 3/5] corrected the endpoint :title --- server.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/server.js b/server.js index f1e0f2675..a64c80d6b 100644 --- a/server.js +++ b/server.js @@ -79,14 +79,16 @@ app.get('/books/author/:author', async (req, res) => { } }); +// Route to get books by title / words of title app.get('/books/title/:title', async (req, res) => { const { title } = req.params; // Get the title from the URL parameter try { - const book = await Book.findOne({ title: title }); // Query the book by title - if (!book) { - return res.status(404).send('Book not found'); // If no book is found, return 404 - } - res.json(book); // Send the book as a JSON response + const books = await Book.find({ + title: {$regex: title, $options: 'i' }}) + if (books.length === 0) { + return res.status(404).send('No books found for this author'); + } + res.json(books); } catch (error) { console.error('Error retrieving book', error); res.status(500).send('Server error'); From 0f6a89c62b63eb0cc595f5609079aff5a0103a2b Mon Sep 17 00:00:00 2001 From: Gitte Beckmann Date: Fri, 13 Dec 2024 11:56:02 +0100 Subject: [PATCH 4/5] added list endpoints and content to README file --- README.md | 16 ++++++++++++---- package.json | 1 + server.js | 10 +++++++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 35019cd8a..c02c17b8b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,20 @@ # Project Mongo API -Replace this readme with your own information about your project. +This project is an Express.js application that provides a RESTful API for interacting with a MongoDB database of books. It allows users to retrieve books by various attributes such as author, title, ISBN, and language. The project also features an optional database reset functionality to seed the database with a predefined set of books. -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +## Features +MongoDB integration for storing and querying books data. -## The problem +CORS enabled for cross-origin requests. -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? +RESTful API endpoints to interact with the books database: +Get all books +Get books by author +Get books by title +Get books by ISBN +Get books by language + +Database seeding: Optionally populate the database with sample data from a books.json file. ## View it live diff --git a/package.json b/package.json index 8eee0dfe3..35fde9b38 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.7", "express": "^4.17.3", + "express-list-endpoints": "^7.1.1", "mongoose": "^8.0.0", "nodemon": "^3.0.1" }, diff --git a/server.js b/server.js index a64c80d6b..451aea046 100644 --- a/server.js +++ b/server.js @@ -8,8 +8,11 @@ dotenv.config() // Connecting to MongoDB // const mongoUrl = process.env.MONGO_URL || 'mongodb://127.0.0.1:27017/books' + +// Connecting to MongoDB Atlas const mongoURI = process.env.MONGODB_URI + mongoose.connect(mongoURI) .then(() => { @@ -33,6 +36,7 @@ const Book = mongoose.model('Book', new mongoose.Schema({ // PORT=9000 npm start const port = process.env.PORT || 8080; const app = express(); +const listEndpoints = require("express-list-endpoints") if (process.env.RESET_DB) { const seedDatabase = async () => { @@ -50,7 +54,11 @@ app.use(express.json()); // Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!"); + const endpoints = listEndpoints(app) + res.json({ + message: "Welcome!", + endpoints: endpoints + }); }); // Route to get books From 7210bb919887df5449b6babf7a8ae8a7480c1b81 Mon Sep 17 00:00:00 2001 From: Gitte Beckmann Date: Fri, 13 Dec 2024 12:06:21 +0100 Subject: [PATCH 5/5] added live view link to README file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c02c17b8b..34c750e59 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,4 @@ Database seeding: Optionally populate the database with sample data from a books ## 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-mongo-api-7ch7.onrender.com/