Lab 2
Mongoose Models and Schemas
Scenario
A local library wants to modernize its book tracking system. They have hired you to build the backend for a new “Digital Bookshelf” application. Your first task is to create a RESTful API that allows librarians to manage their book inventory. This API must support creating new book records, viewing the list of all books, finding a specific book by its ID, updating a book’s information, and removing a book from the collection.
Learning Objectives
By the end of this activity, you will have demonstrated your ability to:
- Define a Mongoose schema with appropriate data types and validation.
- Compile a schema into a Mongoose model.
- Build a full CRUD (Create, Read, Update, Delete) API using Express.
- Implement separate, modular routes for your API endpoints.
- Use Mongoose model methods to interact with a MongoDB database.
- Handle request data from
req.bodyandreq.params.
Instructions
Task 1: Project Setup
- Create a new project directory (e.g.,
digital-bookshelf-api). - Initialize the project with
npm init -y. - Install the required dependencies:
express,mongoose, anddotenv. - Set up your file structure. It’s a good practice to separate your concerns. Create the following:
server.js: The main entry point for your application.db/: A directory to hold your database connection logic.models/: A directory for your Mongoose models.routes/: A directory for your Express route definitions.
- Create a
.envfile and add your MongoDB Atlas connection string to it. - Create a
.gitignorefile and addnode_modules/and.envto it.
Task 2: Database Connection
- In the
db/directory, create aconnection.jsfile. - In this file, use
mongoose.connect()to establish a connection to your database using the URI from your.envfile. Export your connection logic. - In
server.js, require and execute your database connection.
Task 3: Book Schema and Model
- In the
models/directory, create aBook.jsfile. - Define a schema for a
Bookwith the following fields and validation rules:title: AString, which is required.author: AString, which is required.isbn: AString, which must be unique.publishedDate: ADate.inStock: ABoolean, with a default value oftrue.
- Compile this schema into a model named
Bookand export it.
Task 4: API Routes
- In the
routes/directory, create abookRoutes.jsfile. - Use
express.Router()to create a new router instance. - Implement the five core CRUD endpoints on this router:
- Create:
POST /- Creates a new book using the data inreq.body. - Read All:
GET /- Retrieves all books from the database. - Read One:
GET /:id- Retrieves a single book by its_id. - Update:
PUT /:id- Updates a book by its_idusing the data inreq.body. - Delete:
DELETE /:id- Deletes a book by its_id.
- Create:
- Use
async/awaitandtry...catchblocks in all routes to handle errors. - Export the router.
Task 5: Server Configuration
- In
server.js:- Set up your Express application.
- Use the
express.json()middleware to parse request bodies. - Mount your book router at a base path, like
/api/books. - Start the server on a specified port.
Submission Instructions
- Ensure your application runs without errors using
node server.js. - Test all five of your API endpoints using an API client like Postman or Insomnia. Verify that each one performs the correct CRUD operation.
- Submit a link to a GitHub repository containing your complete project. Do not include your
.envfile or thenode_modulesdirectory.
Grading Rubric
| Criteria | Description | Points |
|---|---|---|
| Project Setup (10 points) | ||
| File Structure & Dependencies | Project has the correct modular structure (db/, models/, routes/) and all dependencies are installed. | 5 |
| Database Connection | A separate connection.js file successfully connects to the MongoDB Atlas database on startup. | 5 |
| Schema & Model (10 points) | ||
| Schema Definition | Book.js defines a schema with all required fields (title, author, isbn, etc.). | 5 |
| Schema Validation | title and author are required; isbn is unique; inStock has a default value. | 5 |
| API Endpoints (30 points) | ||
POST /api/books (Create) | Correctly creates and saves a new book document. Responds with the created document and a 201 status. | 6 |
GET /api/books (Read All) | Correctly fetches and returns an array of all book documents. | 6 |
GET /api/books/:id (Read One) | Correctly fetches and returns a single book document by its ID. Handles cases where the ID is not found. | 6 |
PUT /api/books/:id (Update) | Correctly finds a book by ID and updates it with req.body. Returns the updated document. | 6 |
DELETE /api/books/:id (Delete) | Correctly finds a book by ID and deletes it. Returns a confirmation message. | 6 |
| Total | 50 |
Reflection Questions
- Why is it beneficial to separate your routes, models, and database connection into different directories?
- What is the difference between
PUTandPATCHHTTP methods, and which one does yourPUT /:idendpoint more closely resemble? - In the
DELETEroute, what is a good practice for the response you send back to the client after a successful deletion? Should you send the deleted object, a simple success message, or something else? Why?