feat: Add Swagger API documentation

This commit introduces Swagger API documentation for all endpoints in the
application.

- Installs  and .
- Configures Swagger in  to generate and serve API documentation
  at .
- Adds JSDoc-style Swagger annotations to all routes in  and
  the  directory (, , ,
  , , ).
- Defines a cookie-based security scheme for authenticated routes.

This allows for interactive API documentation and testing via the
endpoint.
This commit is contained in:
Adolfo Reyna
2025-07-17 09:52:37 -04:00
parent 0a48327e93
commit 148ed696b2
9 changed files with 1891 additions and 10 deletions

294
index.js
View File

@@ -39,9 +39,119 @@ app.use(limiter);
// Authentication
const { signup, login, logout, resetPassword } = require('./auth/authEmail.js');
/**
* @swagger
* /signup:
* post:
* summary: Signs up a new user
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* password:
* type: string
* format: password
* responses:
* 200:
* description: The user was successfully signed up.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 400:
* description: Bad request.
*/
app.route('/signup').get(signup).post(signup);
/**
* @swagger
* /login:
* post:
* summary: Logs in a user
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* password:
* type: string
* format: password
* responses:
* 200:
* description: The user was successfully logged in.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 401:
* description: Invalid credentials.
*/
app.route('/login').get(login).post(login);
/**
* @swagger
* /logout:
* get:
* summary: Logs out a user
* tags: [Auth]
* responses:
* 200:
* description: The user was successfully logged out.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
*/
app.get('/logout', logout);
/**
* @swagger
* /resetPassword:
* post:
* summary: Resets a user's password
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* responses:
* 200:
* description: A password reset link has been sent to the user's email.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 400:
* description: Bad request.
*/
app.route('/resetPassword').post(resetPassword);
// Routes
@@ -61,6 +171,42 @@ app.use('/songs', sessionChecker, songsRoute);
const subsplashRoute = require('./routes/subsplash.js');
app.use('/subsplash', subsplashRoute);
// Swagger API Docs
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const swaggerDefinition = {
openapi: '3.0.0',
info: {
title: 'EMI Backend API',
version: '1.0.0',
description: 'This is the REST API for the EMI Backend'
},
servers: [
{
url: 'http://localhost:3000',
description: 'Development server'
}
],
components: {
securitySchemes: {
cookieAuth: {
type: 'apiKey',
in: 'cookie',
name: 'user_sid'
}
}
}
};
const options = {
swaggerDefinition,
apis: ['./index.js', './routes/*.js']
};
const swaggerSpec = swaggerJSDoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
// Web Push Notifications
const webPush = require('web-push');
const publicVapidKey = process.env.PUBLIC_VAPID_KEY;
@@ -78,7 +224,31 @@ const DB = require("./mongoDB.js");
DB.getDB.then((DB) => {
console.log("Main logic: DB connected!");
// route for Home-Page
/**
* @swagger
* /:
* get:
* summary: Returns basic information about the logged-in user
* tags: [General]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* userInfo:
* type: object
* profileInfo:
* type: object
* 401:
* description: Unauthorized
*/
app.get('/', sessionChecker, async (req, res) => {
try {
const userInfo = req.userInfo;
@@ -97,7 +267,38 @@ DB.getDB.then((DB) => {
}
});
// Check for an invitation for an email
/**
* @swagger
* /invite/{email}:
* get:
* summary: Checks if an invitation exists for a given email
* tags: [General]
* parameters:
* - in: path
* name: email
* required: true
* schema:
* type: string
* format: email
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* invitation:
* type: object
* 400:
* description: Provide a valid email
* 404:
* description: No invitation found for this email
* 409:
* description: This user is already registered
*/
app.get("/invite/:email", async (req, res) => {
try {
const email = req.params.email.trim().toLowerCase();
@@ -130,7 +331,42 @@ DB.getDB.then((DB) => {
});
// Change the active profile for the user.
/**
* @swagger
* /changeProfile:
* post:
* summary: Changes the active profile for the user
* tags: [General]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* profileid:
* type: string
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* profile:
* type: object
* 400:
* description: Profile ID is required
* 403:
* description: Profile does not belong to the logged-in user
* 404:
* description: Profile does not exist
*/
app.post('/changeProfile', sessionChecker, async (req, res) => {
try {
const user_sid = getUserId(req);
@@ -157,7 +393,38 @@ DB.getDB.then((DB) => {
}
});
// This is the endpoint to refresh the push notification token
/**
* @swagger
* /token:
* post:
* summary: Refreshes the push notification token
* tags: [General]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* token:
* type: string
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 400:
* description: Token is required
* 500:
* description: Failed to update token
*/
app.post('/token/', sessionChecker, async (req, res) => {
try {
const profileid = getProfileId(req);
@@ -179,7 +446,24 @@ DB.getDB.then((DB) => {
}
});
// Used for webpush notifications
/**
* @swagger
* /subscribe:
* post:
* summary: Subscribes a user to webpush notifications
* tags: [General]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* responses:
* 201:
* description: Created
*/
app.post('/subscribe', sessionChecker, async (req, res) => {
const subscription = req.body;
res.status(201).json({});