Skip to content

Song api #1362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: v5
Choose a base branch
from
Open

Song api #1362

wants to merge 2 commits into from

Conversation

Rahulab14
Copy link

Please describe the changes this PR makes and why it should be merged:

Status and versioning classification:

Important.

  • Write in camelCase, not snake_case.
  • Do not push to master/main without testing your changes first, make a branch
    if you have to.

Copy link
Contributor

coderabbitai bot commented May 15, 2025

Walkthrough

A new Mongoose schema and model for songs has been introduced, along with an Express router module that provides endpoints to add, delete, and retrieve songs. The router handles asynchronous database operations for managing a song queue, exposing three RESTful endpoints for interaction.

Changes

File(s) Change Summary
api/models/Songs.js Introduced a Mongoose schema and model for songs with fields: title, artist, url, and addedAt.
api/routes/songs.js Added an Express router with POST /add (add song), POST /delete (delete by ID), and GET /queue (list songs).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Router as Songs Router
    participant DB as MongoDB (Song Model)

    Client->>Router: POST /add (title, artist, url)
    Router->>DB: Create and save Song
    DB-->>Router: Saved Song
    Router-->>Client: 201 Created (Saved Song)

    Client->>Router: POST /delete (id)
    Router->>DB: Delete Song by ID
    alt Song found
        DB-->>Router: Deletion result
        Router-->>Client: Success message
    else Song not found
        DB-->>Router: null
        Router-->>Client: 404 Song not found
    end

    Client->>Router: GET /queue
    Router->>DB: Find all Songs sorted by addedAt
    DB-->>Router: Song list
    Router-->>Client: Song queue
Loading

Poem

In the warren of code, a new song hops in,
Add, delete, or queue—let the playlist begin!
With fields and routes, the music will flow,
From Mongo to Express, the melodies grow.
🐰🎶
Hopping through endpoints, the rabbits all cheer,
For the song queue is live—let’s lend it an ear!

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (2)
api/models/Songs.js (1)

1-13: 💡 Verification agent

🧩 Analysis chain

Fix filename inconsistency

The file is named Songs.js (plural), but it's imported in the routes file as Song.js (singular). This will cause a "module not found" error.

Either rename this file to Song.js or update the import in the routes file:


🏁 Script executed:

#!/bin/bash
# Check if the file exists and confirm the filename inconsistency
ls -la api/models/Song.js api/models/Songs.js

Length of output: 181


🏁 Script executed:

#!/bin/bash
# Search for incorrect model import references across the codebase
rg -n "import .*models/Song" -H
rg -n "require.*models/Song" -H

Length of output: 132


Fix filename inconsistency in model import

The model file is named api/models/Songs.js, but in api/routes/songs.js you’re doing:

const Song = require('../models/Song.js');

That mismatch will throw a MODULE_NOT_FOUND error at runtime.

Please choose one of the following fixes:

  • Rename api/models/Songs.jsapi/models/Song.js
  • Or update line 2 of api/routes/songs.js to:
    const Song = require('../models/Songs.js');
api/routes/songs.js (1)

1-38: 🛠️ Refactor suggestion

Add authentication middleware

These API endpoints have no authentication, allowing anyone to modify the song queue. Consider adding authentication middleware.

Implement authentication middleware to protect these endpoints. Many Discord bots use role-based permissions to control who can add or delete songs from the queue.

// Example middleware (to be defined elsewhere)
const isAuthenticated = (req, res, next) => {
  // Check for authentication
  if (!req.user) {
    return res.status(401).json({ success: false, error: 'Unauthorized' });
  }
  next();
};

// Apply to routes
router.post('/add', isAuthenticated, async (req, res) => {
  // Existing code
});

router.post('/delete', isAuthenticated, async (req, res) => {
  // Existing code
});
🧹 Nitpick comments (2)
api/models/Songs.js (1)

1-3: Check coding style consistency

There are two empty lines at the beginning of the file. Consider removing them for consistency.

api/routes/songs.js (1)

28-35: Add pagination to queue endpoint

For large datasets, retrieving all songs at once could impact performance. Consider implementing pagination.

router.get('/queue', async (req, res) => {
  try {
-   const queue = await Song.find().sort({ addedAt: 1 }); // oldest to newest
+   const page = parseInt(req.query.page) || 1;
+   const limit = parseInt(req.query.limit) || 20;
+   const skip = (page - 1) * limit;
+   
+   const queue = await Song.find()
+     .sort({ addedAt: 1 })
+     .skip(skip)
+     .limit(limit);
+   
+   const total = await Song.countDocuments();
+   
-   res.json({ success: true, queue });
+   res.json({ 
+     success: true, 
+     queue,
+     pagination: {
+       currentPage: page,
+       totalPages: Math.ceil(total / limit),
+       totalItems: total
+     }
+   });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 4253446 and 25dc562.

📒 Files selected for processing (2)
  • api/models/Songs.js (1 hunks)
  • api/routes/songs.js (1 hunks)
🔇 Additional comments (1)
api/models/Songs.js (1)

5-10: Schema definition looks good

The schema includes all necessary fields with appropriate types and validation rules.

addedAt: { type: Date, default: Date.now }
});

export default mongoose.model('Song', SongSchema);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix export syntax for CommonJS compatibility

This export uses ES Module syntax, but needs to use CommonJS syntax to be compatible with the routes file.

-export default mongoose.model('Song', SongSchema);
+module.exports = mongoose.model('Song', SongSchema);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default mongoose.model('Song', SongSchema);
module.exports = mongoose.model('Song', SongSchema);
🤖 Prompt for AI Agents
In api/models/Songs.js at line 12, the export uses ES Module syntax which is
incompatible with CommonJS used in the routes file. Change the export statement
to use CommonJS syntax by replacing "export default" with "module.exports =".
This will ensure compatibility with the rest of the codebase.

@@ -0,0 +1,12 @@


import mongoose from 'mongoose';
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix import/export inconsistency

This file uses ES Module syntax (import/export), but the routes file uses CommonJS (require/module.exports). This will cause runtime errors.

-import mongoose from 'mongoose';
+const mongoose = require('mongoose');

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In api/models/Songs.js at line 3, the file uses ES Module syntax with `import`,
but the routes file uses CommonJS syntax. To fix the import/export inconsistency
and avoid runtime errors, convert the import statement to CommonJS by replacing
`import mongoose from 'mongoose';` with `const mongoose = require('mongoose');`
and ensure exports use `module.exports` instead of ES `export` syntax.

Comment on lines +6 to +15
router.post('/add', async (req, res) => {
try {
const { title, artist, url } = req.body;
const song = new Song({ title, artist, url });
await song.save();
res.status(201).json({ success: true, song });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add input validation for the add endpoint

The current implementation relies only on Mongoose schema validation. Consider adding explicit validation for the request body.

router.post('/add', async (req, res) => {
  try {
    const { title, artist, url } = req.body;
+   // Validate required fields
+   if (!title || !url) {
+     return res.status(400).json({ success: false, error: 'Title and URL are required' });
+   }
+   // Validate URL format
+   if (!url.match(/^(http|https):\/\/[^ "]+$/)) {
+     return res.status(400).json({ success: false, error: 'Invalid URL format' });
+   }
    const song = new Song({ title, artist, url });
    await song.save();
    res.status(201).json({ success: true, song });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
router.post('/add', async (req, res) => {
try {
const { title, artist, url } = req.body;
const song = new Song({ title, artist, url });
await song.save();
res.status(201).json({ success: true, song });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
router.post('/add', async (req, res) => {
try {
const { title, artist, url } = req.body;
// Validate required fields
if (!title || !url) {
return res.status(400).json({ success: false, error: 'Title and URL are required' });
}
// Validate URL format
if (!url.match(/^(http|https):\/\/[^ "]+$/)) {
return res.status(400).json({ success: false, error: 'Invalid URL format' });
}
const song = new Song({ title, artist, url });
await song.save();
res.status(201).json({ success: true, song });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
🤖 Prompt for AI Agents
In api/routes/songs.js around lines 6 to 15, the POST /add endpoint lacks
explicit input validation for the request body. Add validation logic before
creating the Song instance to check that title, artist, and url are present and
meet any required format or constraints. If validation fails, respond with a 400
status and an appropriate error message instead of proceeding to save the song.

Comment on lines +16 to +26
//post delete a song
router.post('/delete', async (req, res) => {
try {
const { id } = req.body;
const deleted = await Song.findByIdAndDelete(id);
if (!deleted) return res.status(404).json({ success: false, message: 'Song not found' });
res.json({ success: true, message: 'Song deleted' });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use RESTful conventions for delete operation

Using POST for delete operations doesn't follow RESTful conventions. Consider using DELETE HTTP method and route parameters instead of a request body.

-//post delete a song
-router.post('/delete', async (req, res) => {
+// Delete a song by ID
+router.delete('/:id', async (req, res) => {
  try {
-   const { id } = req.body;
+   const { id } = req.params;
    const deleted = await Song.findByIdAndDelete(id);
    if (!deleted) return res.status(404).json({ success: false, message: 'Song not found' });
    res.json({ success: true, message: 'Song deleted' });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//post delete a song
router.post('/delete', async (req, res) => {
try {
const { id } = req.body;
const deleted = await Song.findByIdAndDelete(id);
if (!deleted) return res.status(404).json({ success: false, message: 'Song not found' });
res.json({ success: true, message: 'Song deleted' });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
// Delete a song by ID
router.delete('/:id', async (req, res) => {
try {
const { id } = req.params;
const deleted = await Song.findByIdAndDelete(id);
if (!deleted) return res.status(404).json({ success: false, message: 'Song not found' });
res.json({ success: true, message: 'Song deleted' });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
🤖 Prompt for AI Agents
In api/routes/songs.js around lines 16 to 26, the delete operation uses a POST
method with the song ID in the request body, which is not RESTful. Change the
route to use the DELETE HTTP method and pass the song ID as a route parameter
(e.g., '/delete/:id'). Update the handler to extract the ID from req.params
instead of req.body.

Comment on lines +1 to +2
const express = require('express');
const Song = require('../models/Song.js');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix import path and module compatibility

There are two critical issues with the imports:

  1. The import path for the Song model is incorrect. It's importing from Song.js but the file is named Songs.js (plural)
  2. You're trying to import an ES Module with CommonJS syntax, which will fail
-const Song = require('../models/Song.js');
+const Song = require('../models/Songs.js');

Alternatively, make both files use the same module system (either both CommonJS or both ES Modules).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const express = require('express');
const Song = require('../models/Song.js');
const express = require('express');
const Song = require('../models/Songs.js');
🤖 Prompt for AI Agents
In api/routes/songs.js at lines 1 to 2, fix the import path by changing
'Song.js' to 'Songs.js' to match the actual filename. Also, ensure module
compatibility by either converting this file to use ES Module syntax
(import/export) if Songs.js is an ES Module, or convert Songs.js to CommonJS
exports so both use the same module system. This will prevent import errors due
to mixing module types.

//post delete a song
router.post('/delete', async (req, res) => {
try {
const { id } = req.body;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Validate MongoDB ObjectId

Without validation, invalid ID formats will cause Mongoose to throw an error. Add validation to provide better error messages.

try {
  const { id } = req.body;
+ // Validate MongoDB ObjectId format
+ if (!id.match(/^[0-9a-fA-F]{24}$/)) {
+   return res.status(400).json({ success: false, error: 'Invalid song ID format' });
+ }
  const deleted = await Song.findByIdAndDelete(id);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { id } = req.body;
try {
const { id } = req.body;
// Validate MongoDB ObjectId format
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
return res.status(400).json({ success: false, error: 'Invalid song ID format' });
}
const deleted = await Song.findByIdAndDelete(id);
// ...rest of your logic
}
🤖 Prompt for AI Agents
In api/routes/songs.js at line 19, the code extracts the id from req.body but
does not validate if it is a valid MongoDB ObjectId. To fix this, add a check
using Mongoose's ObjectId.isValid method before proceeding. If the id is
invalid, return a clear error response to the client instead of letting Mongoose
throw an error.

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