In this task, you will extend the Posts API to manage relational data by adding support for Comments. Comments are associated with Posts, creating a one-to-many relationship between the two entities. You will update the database schema, seed the database with sample data, implement CRUD operations for Comments, and handle relational data operations.
In a relational database, entities are often related to each other through relationships. In this task, we will model a one-to-many relationship between Posts and Comments. Each Post can have multiple Comments associated with it, but each Comment belongs to only one Post.
There are three main types of relationships in relational databases:
In our case, the relationship between Posts and Comments is a one-to-many relationship. An example of a one-to-one relationship could be a User and their Profile, where each User has one Profile. A many-to-many relationship could be between Posts and Tags, where each Post can have multiple Tags, and each Tag can be associated with multiple Posts.
When modeling relational data, it’s essential to consider the cardinality of the relationship (one-to-one, one-to-many, many-to-many) and the referential integrity constraints (e.g., foreign keys) to maintain data consistency.
To model the one-to-many relationship between Posts and Comments, we need to update the database schema (src/db/schema.ts
) to include the Comments table and establish the relationship between the two tables using foreign keys.
In the comments
table definition:
id
column is the primary key for the Comments table.content
column stores the text content of the Comment.date
column stores the timestamp when the Comment was created.postId
column is a foreign key that references the id
column of the Posts table.By defining the postId
column as a foreign key that references the id
column of the Posts table, we establish the one-to-many relationship between Posts and Comments. This relationship ensures that each Comment is associated with a specific Post.
After updating the schema, you need to run the migration to apply the changes to the database. Since we are at early stages of development, you can use pnpm run db:push
to recreate the database with the updated schema instead of running a migration.
To test the app, we need to seed the database with sample data. Let’s update src/db/seed.ts
to insert sample Posts and Comments into the database.
Make sure to run npm run db:seed
to populate the database with sample data.
Before implementing routes for Comments, update the input validation schemas for creating, updating, and retrieving Comments. Add the following schemas to src/validators/schemas.ts
:
These schemas define the structure and constraints for creating, updating, and retrieving Comments. The createCommentSchema
schema specifies that the content
field is required and must be between 1 and 120 characters long. The updateCommentSchema
schema is a partial schema that allows updating only the content
field. The getCommentsSchema
schema defines the structure for retrieving all Comments for a specific Post. The getCommentSchema
schema defines the structure for retrieving a single Comment by ID for a specific Post.
Now that you have updated the database schema, seeded the database with sample data, and defined the input validation schemas for Comments, you can implement CRUD operations for Comments. Add the following routes to
src/routes/comments.ts
.
Add a route to retrieve all Comments for a specific Post:
Notice the API endpoint is /posts/:postId/comments
, where :postId
is the ID of the Post for which you want to retrieve the Comments. We could have used /comments?postId=:postId
as well, but the former is more RESTful. The route handler fetches all Comments associated with the specified Post and returns them as a JSON response.
Add a route to retrieve a single Comment by ID for a specific Post:
In this route, the API endpoint is /posts/:postId/comments/:commentId
, where :postId
is the ID of the Post and :commentId
is the ID of the Comment you want to retrieve. The route handler fetches the Comment with the specified ID for the specified Post and returns it as a JSON response. If the Comment is not found, it throws a 404 Not Found
error.
Add a route to delete a Comment by ID for a specific Post:
In this route, the API endpoint is /posts/:postId/comments/:commentId
, where :postId
is the ID of the Post and :commentId
is the ID of the Comment you want to delete. The route handler deletes the Comment with the specified ID for the specified Post and returns the deleted Comment as a JSON response. If the Comment is not found, it throws a 404 Not Found
error.
Add a route to create a new Comment for a specific Post:
In this route, the API endpoint is /posts/:postId/comments
, where :postId
is the ID of the Post for which you want to create a new Comment. The route handler extracts the postId
from the request parameters and the content
from the request body. It then creates a new Comment with the specified content, current date, and Post ID and returns the newly created Comment as a JSON response.
Add a route to update an existing Comment by ID for a specific Post:
In this route, the API endpoint is /posts/:postId/comments/:commentId
, where :postId
is the ID of the Post and :commentId
is the ID of the Comment you want to update. The route handler extracts the postId
and commentId
from the request parameters and the content
from the request body. It then updates the Comment with the specified ID for the specified Post with the new content and returns the updated Comment as a JSON response. If the Comment is not found, it throws a 404 Not Found
error.
Similar to the previous tasks, you can implement search, sort, filter, and pagination functionality for the Comments resource. This will allow clients to query the Comments data based on specific criteria and retrieve the results in a structured manner. This is left as an exercise for you to complete.
When a Post is deleted, you should also delete all associated Comments. This is known as a cascade delete operation. You can implement this functionality by updating the delete
operation for Posts to also delete all associated Comments.
Alternatively, you can configure the foreign key constraint in the database schema to perform a cascade delete automatically when a Post is deleted. Update the foreign key definition in the comments
table to specify the onDelete: "cascade"
option:
With this configuration, when a Post is deleted, all associated Comments will be automatically deleted by the database engine.
In this task, you extended the Posts API to manage relational data by adding support for Comments. You updated the database schema to model the one-to-many relationship between Posts and Comments, seeded the database with sample data, implemented CRUD operations for Comments, and handled relational data operations. By managing relational data effectively, you can build more complex and feature-rich applications that leverage the power of relational databases.