In this challenge, you will add Tags to the Noteful app, populate the notes with tags, create routes and tests for the tags and update the routes and test for the notes.
- Create tag schema, update notes schema and then seed the database
- Create tags endpoints and update notes endpoints
- Update
server.jsto mount tags router - Update the client
Since you created a similar schema and model for Notes and Folders we will keep the instructions brief.
Create a /models/tags.js file and create a tagsSchema with the following specs:
- Create a
/models/tags.jsfile for the Schema and Model. - Create a simple
tagSchemaand define anamefield with the following criteria:- Type is
String - Required is
true - Unique is
true
- Type is
- Create timestamps fields
createdAtandupdatedAtusing the Mongoose timestamps option - Configure the Mongoose
toObjectoption to transform the doc:- Include
virtualslikeidto show in the output - Suppress the
__vversion key - Delete the
_idfrom the return object
- Include
- Create
Tagmodel using thetagSchemaand export it
Next you will create Tags seed data and update Notes seed data with tags.
- Create
/db/seed/tags.jsonfile - Add seed data like the following example.
[
{
"_id": "222222222222222222222200",
"name": "breed"
},
{
"_id": "222222222222222222222201",
"name": "hybrid"
},
{
"_id": "222222222222222222222202",
"name": "domestic"
},
{
"_id": "222222222222222222222203",
"name": "feral"
}
]Now that you have defined a Tag Schema and Model, you can add a tags field to the Notes Schema.
In /models/note.js, update the noteSchema as follows:
- Define a
tagsfield:- Array of
ObjectId - References
Tagmodel
- Array of
tags: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Tag' }],Let's update the notes.json. Below is a sample note with its tags set to the _id for foo, bar, and baz. Update the sample data in your seed data file with tags info
{
"_id": "000000000000000000000003",
"title": "7 things lady gaga has in common with cats",
"content": "Posuere sollicitudin aliquam ultrices sagittis orci a. Feugiat sed lectus vestibulum mattis ullamcorper velit. Odio pellentesque diam volutpat commodo sed egestas egestas fringilla. Velit egestas dui id ornare arcu odio. Molestie at elementum eu facilisis sed odio morbi. Tempor nec feugiat nisl pretium. At tempor commodo ullamcorper a lacus. Egestas dui id ornare arcu odio. Id cursus metus aliquam eleifend. Vitae sapien pellentesque habitant morbi tristique. Dis parturient montes nascetur ridiculus. Egestas egestas fringilla phasellus faucibus scelerisque eleifend. Aliquam faucibus purus in massa tempor nec feugiat nisl.",
"folderId": "111111111111111111111101",
"tags": ["222222222222222222222200", "222222222222222222222201", "222222222222222222222202"]
},Update the /utils/seed-database.js file to insert tags and create an index. The index Tag.createIndexes() call tells mongo to create an index immediately which is used enforce the unique rule on Tag names.
Below is a simple and reliable way to seed the database and trigger indexing. Update your /utils/seed-database.js file to require the Tag model and seed data. And then update it to insert Tags and create an index as shown below.
// ... REMOVED FOR BREVITY
mongoose.connect(MONGODB_URI)
.then(() => mongoose.connection.db.dropDatabase())
.then(() => {
return Promise.all([
Note.insertMany(seedNotes),
Folder.insertMany(seedFolders),
Tag.insertMany(seedTags),
Folder.createIndexes(),
Tag.createIndexes()
]);
})
// ... REMOVED FOR BREVITYConfirm the seed process worked correctly by verifying the data using Mongo shell or your favorite database GUI.
Your next challenge is to create Folder endpoints and integration tests.
Create a new /routes/tags.js file to hold the endpoints and mount it on server.js. In the file, create the following CRUD endpoints.
GETall/tags- Sort the response by
name
- Sort the response by
GET/tagsbyid- Add validation that protects against invalid Mongo ObjectIds and prevents unnecessary database queries.
- Add condition that checks the result and returns a 200 response with the result or a 404 Not Found
POST/tagsto create a new tag- Add validation that protects against missing
namefield - A successful insert returns a
locationheader and a 201 status - Add condition that checks for a
duplicate key errorwith code11000and responds with a helpful error message
- Add validation that protects against missing
PUT/tagsbyidto update a tag- Add validation which protects against missing
namefield - Add validation which protects against an invalid ObjectId
- Add condition that checks the result and returns a 200 response with the result or a 404 Not Found
- Ensure you are returning the updated/modified document, not the document prior to the update
- Add condition that checks for a
duplicate key errorwith code11000and responds with a helpful error message
- Add validation which protects against missing
DELETE/tagsbyiddeletes the tag AND removes it from thenotescollection- Remove the tag
- Using
$pull, remove the tag from thetagsarray in thenotescollection. - Add condition that checks the result and returns a 200 response with the result or a 204 status
GETall/notes- Add
tagsto the response - Use
.populate()to populate the tags array - Capture the incoming
tagIdand conditionally add it to the database query filter
- Add
GET/notesby id- Add
tagsto the response - Use
.populate()to populate the tags array
- Add
POST/notes- Capture
tagsfrom request body - Verify each tag id is a valid
ObjectIdand, if necessary, return a user-friendly response with a 400 status - Save
tagsalong with the othernotefields
- Capture
PUT/notes- Capture
tagsfrom request body - Verify each tag id is a valid
ObjectIdand, if necessary, return a user-friendly response with a 400 status - Save
tagsalong with the othernotefields
- Capture
DELETE/notes- No change :)
Create a /test/tags.js file, the basic structure in similar to /test/folders.js. Update the require statements and the Mocha life-cycle hooks to use Tag models and tags seed data.
Create tests to verify the functionality of the /tags endpoints. As your work through the tests, check the code coverage for clues on which aspects of your code you have validated and which still needs tests.
Don't forget to update /test/notes.js. You added new features to these endpoints earlier and that functionality needs to be tested to ensure it continues to work properly.
- Update the require statements to include tags.
- Update the life-cycle hooks to seed the database with notes, folders and tags
- Update the tests to verify tag related features
Check your code coverage. Are there any lines of code which are not covered by tests? Create tests for any outstanding features.
Finally, uncomment the tags search on /public/index.js.
Promise.all([
api.search('/api/notes'),
api.search('/api/folders'),
api.search('/api/tags')
])