Skip to content

add solution#127

Closed
ghost wants to merge 1 commit into
masterfrom
unknown repository
Closed

add solution#127
ghost wants to merge 1 commit into
masterfrom
unknown repository

Conversation

@ghost
Copy link
Copy Markdown

@ghost ghost commented Aug 9, 2025

No description provided.

Copy link
Copy Markdown

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This is an educational approval to help you continue moving forward. You've done a fantastic job building a solid backend with a clean project structure and a well-designed RESTful API. This is a great foundation!

The feedback below focuses on a few critical areas and suggestions that will help you build even more robust and professional applications. Please note that the required client-side application was missing from the submission; be sure to include it in the future to demonstrate the full functionality.

🔴 Critical Issues to Address

These are important issues that affect the core functionality and architecture of your application.

1. WebSocket Logic Causes Duplicate Messages

  • File: src/index.js, line 39
  • Issue: The line rooms[roomId].push(ws) is inside the 'message' event listener. This means every time a client sends a message, they are added to the room's client list again.
  • Impact: This causes the client to receive an increasing number of duplicate messages for every new message sent in the room.
  • Suggestion: A client should only be added to a room once. Consider creating a separate "join room" event that the client sends upon connecting to a room. The regular "message" event should only broadcast the message, not modify the list of clients in the room.

2. Bypassing the Service Layer in WebSocket Handler

  • File: src/index.js, line 43
  • Issue: The code await Message.findAll({ where: { roomId } }) calls the database model directly from your main server file.
  • Impact: This breaks the application's architectural pattern (Controller -> Service -> Model). All database logic should be contained within your service files to keep your code organized, maintainable, and testable.
  • Suggestion: Import your messageService and use the existing function you already created: await messageService.getAllMessagesInRoom(roomId).

3. Missing Data Integrity Checks in Services

  • Files: src/services/message.service.js, src/services/rooms.service.js
  • Issue: The service functions that create new records (e.g., createMessageInRoom, createRoom) trust that the IDs provided (userId, roomId) are valid and exist in the database.
  • Impact: If a request comes in with a non-existent userId, you could create an "orphaned" record that is not properly linked to a user, leading to data integrity problems and potential application errors.
  • Suggestion: Before creating a record, add a quick check to ensure the related entities exist. For example, in createMessageInRoom, first check that a user with userId and a room with roomId exist. If not, throw an error that the controller can handle.

💡 Suggestions for Improvement

These are opportunities to make your code more conventional, robust, and efficient.

1. Use Correct HTTP Status Codes for Client Errors

  • Files: src/controllers/message.controller.js (line 9), src/controllers/rooms.controller.js (line 13), src/controllers/user.controller.js (line 9)
  • Issue: You are returning a 404 Not Found status when a required field is missing from the request body.
  • Suggestion: A 404 Not Found status should be reserved for when the requested resource (the URL) cannot be found. For malformed client requests (like missing fields), the correct status code is 400 Bad Request.

2. Move Business Logic from Controllers to Services

  • File: src/controllers/user.controller.js, line 6
  • Issue: The logic to check if a user already exists (User.findOne(...)) is in the controller.
  • Suggestion: This is a piece of business logic that belongs in the userService. The service should be responsible for checking for duplicates before creating a new user. This keeps your controllers "thin" and focused only on handling the HTTP request and response.

3. Configure Cascading Deletes in Models

  • Files: src/models/message.js, src/models/room.js
  • Issue: Your model associations don't specify what should happen to messages if their parent Room or User is deleted. This can lead to orphaned data in your database.
  • Suggestion: Add onDelete: 'CASCADE' to your belongsTo associations. This tells the database to automatically delete all of a user's messages or rooms if that user is deleted, ensuring data integrity.
    // Example in message.js
    Message.belongsTo(models.Room, {
      foreignKey: 'roomId',
      onDelete: 'CASCADE', // Add this line
    });

Overall, this is a very strong submission that shows a great understanding of Node.js, Express, and Sequelize. Keep up the excellent work! These suggestions are all part of the journey to becoming an expert developer. Looking forward to seeing your next project


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Footnotes

  1. Rate AI review example

const { text, userId } = req.body;

if (!roomId || !userId || !text) {
return res.sendStatus(404);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For missing required fields in the request body or parameters, it's more appropriate to return a 400 Bad Request status code. The 404 Not Found status should be reserved for when the requested resource (i.e., the URL endpoint itself) cannot be found.

const { title, userId, description } = req.body;

if (!title || !userId) {
return res.sendStatus(404);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When required fields like title or userId are missing from the request body, it's more appropriate to return a 400 Bad Request status code. The 404 Not Found status should be reserved for when the requested resource (i.e., the URL endpoint itself) cannot be found.

const { title, description } = req.body;

if ((!title && !description) || !roomId) {
return res.sendStatus(404);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the createRoom function, if the request is malformed (e.g., no updateable fields provided or roomId is missing), a 400 Bad Request status is more appropriate than 404 Not Found.


const create = async (req, res) => {
const { name } = req.body;
const isNameExist = await User.findOne({ where: { name } });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic to check for an existing user is a piece of business logic that should be encapsulated within the userService. Moving this User.findOne call into the service layer will improve the separation of concerns, making the controller leaner and the service layer more comprehensive.

const isNameExist = await User.findOne({ where: { name } });

if (!name) {
return res.sendStatus(404);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a required field like name is missing from the request body, the appropriate HTTP status code is 400 Bad Request. The 404 Not Found status should be reserved for cases where the requested resource (e.g., the URL endpoint) does not exist.

Comment on lines +7 to +8
const createMessageInRoom = (text, userId, roomId) => {
return Message.create({ text, userId, roomId });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before creating a message, it's crucial to validate that the provided userId and roomId correspond to existing records in the database. Adding checks to ensure the user and room exist will prevent the creation of orphaned messages and improve the overall data integrity of the application. This logic belongs in the service layer.

import { Room } from '../models/room.js';

const getAllRooms = () => {
return Room.findAll();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To provide richer data to the client, consider eager-loading the associated user data. By changing the query to Room.findAll({ include: User }), you can include the details of the user who created each room, reducing the need for follow-up API calls from the client.

Comment on lines +7 to +8
const createRoom = (title, userId, description = '') => {
return Room.create({ title, userId, description });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service currently trusts that the provided userId is valid. To ensure data integrity, you should add a check to verify that a user with the given userId exists before attempting to create the room. This prevents potential foreign key constraint violations and ensures every room has a valid creator.

Comment on lines +15 to +34
const updateRoom = (id, title, description) => {
if (!id) {
throw new Error('Room id is required');
}

const updatedData = {};

if (title) {
updatedData.title = title;
}

if (description) {
updatedData.description = description;
}

if (Object.keys(updatedData).length === 0) {
throw new Error('At least one field must be provided');
}

return Room.update(updatedData, { where: { id } });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before attempting to update a room, it is good practice to first verify that a room with the given id exists. This allows you to provide a more specific error message, such as 'Room not found', which can then be handled appropriately in the controller (e.g., with a 404 status code). The current implementation doesn't distinguish between an update on a non-existent room and a successful update that changes no data.

Comment on lines +3 to +5
const createUser = async (name) => {
return User.create({ name });
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To improve separation of concerns, the logic for checking if a user already exists should be moved from the controller into this function. The createUser function should first query the database to see if a user with the given name already exists. If so, it should throw an error, which the controller can then catch and translate into a 409 Conflict response. This makes the service layer responsible for all business logic related to user creation.

@ghost ghost closed this by deleting the head repository Apr 4, 2026
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant