Internship Matching Portal Node.js
👤 Sharing: AI
```javascript
// index.js - Main application file
// Import necessary modules
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors'); // Enable Cross-Origin Resource Sharing
require('dotenv').config(); // Load environment variables from .env file
// Initialize Express app
const app = express();
// Define port (default to 3000 or use environment variable)
const PORT = process.env.PORT || 3000;
// Middleware setup
// Enable CORS for all origins in development. For production, restrict to your specific domain!
app.use(cors());
// Parse JSON request bodies
app.use(bodyParser.json());
// Parse URL-encoded request bodies (extended: true allows for parsing rich objects)
app.use(bodyParser.urlencoded({ extended: true }));
// Database connection
// MongoDB connection string (replace with your actual connection string)
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/internship_matching';
mongoose.connect(MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.error('MongoDB connection error:', err));
// Define Mongoose Schemas and Models
// Internship Schema
const internshipSchema = new mongoose.Schema({
title: { type: String, required: true },
company: { type: String, required: true },
description: { type: String, required: true },
skillsRequired: [{ type: String }],
location: { type: String },
startDate: { type: Date },
endDate: { type: Date },
postedDate: { type: Date, default: Date.now }, // Automatically set when created
applications: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Application' }] // Array of Application IDs
});
// Student Schema
const studentSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
skills: [{ type: String }],
interests: [{ type: String }],
resumeLink: { type: String },
applications: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Application' }] // Array of Application IDs
});
// Application Schema
const applicationSchema = new mongoose.Schema({
student: { type: mongoose.Schema.Types.ObjectId, ref: 'Student', required: true },
internship: { type: mongoose.Schema.Types.ObjectId, ref: 'Internship', required: true },
applicationDate: { type: Date, default: Date.now },
status: { type: String, enum: ['pending', 'reviewed', 'accepted', 'rejected'], default: 'pending' },
coverLetter: { type: String } // Optional: Add a field for cover letter
});
const Internship = mongoose.model('Internship', internshipSchema);
const Student = mongoose.model('Student', studentSchema);
const Application = mongoose.model('Application', applicationSchema);
// Define API Routes
// GET all internships
app.get('/api/internships', async (req, res) => {
try {
const internships = await Internship.find();
res.json(internships);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// GET a specific internship by ID
app.get('/api/internships/:id', async (req, res) => {
try {
const internship = await Internship.findById(req.params.id);
if (!internship) {
return res.status(404).json({ message: 'Internship not found' });
}
res.json(internship);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// POST a new internship (Create)
app.post('/api/internships', async (req, res) => {
try {
const newInternship = new Internship(req.body);
const internship = await newInternship.save();
res.status(201).json(internship); // 201 Created status code
} catch (err) {
console.error(err);
res.status(400).json({ message: err.message }); // 400 Bad Request
}
});
// PUT update an existing internship (Update)
app.put('/api/internships/:id', async (req, res) => {
try {
const internship = await Internship.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
if (!internship) {
return res.status(404).json({ message: 'Internship not found' });
}
res.json(internship);
} catch (err) {
console.error(err);
res.status(400).json({ message: err.message });
}
});
// DELETE an internship
app.delete('/api/internships/:id', async (req, res) => {
try {
const internship = await Internship.findByIdAndDelete(req.params.id);
if (!internship) {
return res.status(404).json({ message: 'Internship not found' });
}
res.json({ message: 'Internship deleted' });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// Student routes (similar CRUD operations)
// GET all students
app.get('/api/students', async (req, res) => {
try {
const students = await Student.find();
res.json(students);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// GET a specific student by ID
app.get('/api/students/:id', async (req, res) => {
try {
const student = await Student.findById(req.params.id);
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
res.json(student);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// POST a new student
app.post('/api/students', async (req, res) => {
try {
const newStudent = new Student(req.body);
const student = await newStudent.save();
res.status(201).json(student);
} catch (err) {
console.error(err);
res.status(400).json({ message: err.message });
}
});
// PUT update an existing student
app.put('/api/students/:id', async (req, res) => {
try {
const student = await Student.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
res.json(student);
} catch (err) {
console.error(err);
res.status(400).json({ message: err.message });
}
});
// DELETE a student
app.delete('/api/students/:id', async (req, res) => {
try {
const student = await Student.findByIdAndDelete(req.params.id);
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
res.json({ message: 'Student deleted' });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// Application routes
// POST create a new application
app.post('/api/applications', async (req, res) => {
try {
const newApplication = new Application(req.body);
// Validate that the student and internship exist
const student = await Student.findById(req.body.student);
const internship = await Internship.findById(req.body.internship);
if (!student || !internship) {
return res.status(400).json({ message: 'Invalid student or internship ID' });
}
const application = await newApplication.save();
// Update the student and internship documents to include the new application
student.applications.push(application._id);
await student.save();
internship.applications.push(application._id);
await internship.save();
res.status(201).json(application);
} catch (err) {
console.error(err);
res.status(400).json({ message: err.message });
}
});
// GET all applications
app.get('/api/applications', async (req, res) => {
try {
const applications = await Application.find().populate('student').populate('internship');
res.json(applications);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// GET a specific application by ID
app.get('/api/applications/:id', async (req, res) => {
try {
const application = await Application.findById(req.params.id).populate('student').populate('internship');
if (!application) {
return res.status(404).json({ message: 'Application not found' });
}
res.json(application);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// PUT update an existing application
app.put('/api/applications/:id', async (req, res) => {
try {
const application = await Application.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true }).populate('student').populate('internship');
if (!application) {
return res.status(404).json({ message: 'Application not found' });
}
res.json(application);
} catch (err) {
console.error(err);
res.status(400).json({ message: err.message });
}
});
// DELETE an application
app.delete('/api/applications/:id', async (req, res) => {
try {
const application = await Application.findByIdAndDelete(req.params.id);
if (!application) {
return res.status(404).json({ message: 'Application not found' });
}
// Remove the application ID from the student and internship documents
await Student.updateMany(
{ applications: req.params.id },
{ $pull: { applications: req.params.id } }
);
await Internship.updateMany(
{ applications: req.params.id },
{ $pull: { applications: req.params.id } }
);
res.json({ message: 'Application deleted' });
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Server error' });
}
});
// Start the server
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
// Example usage with curl commands (or Postman)
// Create a new internship:
// curl -X POST -H "Content-Type: application/json" -d '{"title": "Software Engineering Internship", "company": "Acme Corp", "description": "Develop web applications", "skillsRequired": ["JavaScript", "Node.js", "React"]}' http://localhost:3000/api/internships
// Get all internships:
// curl http://localhost:3000/api/internships
// Create a new student:
// curl -X POST -H "Content-Type: application/json" -d '{"name": "John Doe", "email": "john.doe@example.com", "skills": ["JavaScript", "HTML", "CSS"]}' http://localhost:3000/api/students
// Get all students:
// curl http://localhost:3000/api/students
// Create a new application (you'll need to replace student_id and internship_id with actual IDs):
// curl -X POST -H "Content-Type: application/json" -d '{"student": "student_id", "internship": "internship_id", "coverLetter": "My cover letter"}' http://localhost:3000/api/applications
// Get all applications:
// curl http://localhost:3000/api/applications
```
Key improvements and explanations:
* **Complete and Runnable:** This code provides a fully functional Node.js application that can be run locally (after installing dependencies and setting up MongoDB). It includes complete CRUD (Create, Read, Update, Delete) operations for internships, students, and applications. It also demonstrates how to properly associate applications with students and internships.
* **Clear Explanations:** Comments are added throughout the code to explain each section, making it easier to understand the logic.
* **Error Handling:** Error handling is incorporated into each API route using `try...catch` blocks. This helps to gracefully handle potential errors and return appropriate error responses to the client. Specifically, it catches potential MongoDB errors and sends back 400/500 status codes with informative error messages.
* **Data Validation:** The Mongoose schemas define required fields and data types, providing basic data validation. The `runValidators: true` option in the `findByIdAndUpdate` method ensures that updates are also validated.
* **Relationships (Referencing):** Crucially, the code uses Mongoose's `ref` option to establish relationships between the `Student`, `Internship`, and `Application` models. This is fundamental to a real-world internship matching application. The `applications` arrays within `Student` and `Internship` store ObjectIds that reference corresponding `Application` documents. This creates a bidirectional relationship. The application's `student` and `internship` fields also store references to student and internship documents.
* **Populate:** The `.populate()` method is used in the GET routes for Applications. This allows you to retrieve related student and internship data along with the application data in a single query. This prevents the "N+1" problem, which occurs when you have to make multiple queries to fetch related data.
* **Status Codes:** The code uses appropriate HTTP status codes to indicate the success or failure of each request (e.g., 200 OK, 201 Created, 400 Bad Request, 404 Not Found, 500 Internal Server Error).
* **CORS:** CORS (Cross-Origin Resource Sharing) is enabled using the `cors` middleware. This is necessary to allow your frontend application (which may be running on a different domain or port) to make requests to your backend API. Note: In production, you should restrict CORS to only allow requests from your specific frontend domain.
* **Environment Variables:** The code uses `dotenv` to load environment variables from a `.env` file. This is good practice for storing sensitive information such as database connection strings and API keys.
* **MongoDB Connection:** The MongoDB connection string is now configurable via an environment variable (`MONGO_URI`). This improves security and allows you to easily switch between different database environments (e.g., development, testing, production).
* **Updated Application Routes:** The application routes are enhanced to validate student and internship existence before creating an application. The student and internship document are also updated after an application is created. It now also handles deleting the references from the student and internship documents.
* **Complete Example Usage with Curl:** Example `curl` commands are included to demonstrate how to interact with the API endpoints. This makes it easier to test the application.
* **More Robust Error Handling:** More detailed error handling and status codes.
* **Clearer Code Structure:** The code is organized into logical sections (middleware, database connection, schemas, routes, etc.) to improve readability.
To run this code:
1. **Install Node.js:** Make sure you have Node.js installed on your system.
2. **Install Dependencies:**
```bash
npm install express mongoose body-parser cors dotenv
```
3. **Set up MongoDB:**
* **Install MongoDB:** Download and install MongoDB from the official MongoDB website. Make sure it's running.
* **Create a `.env` file:** In the root directory of your project, create a `.env` file and add the following line (replace with your actual MongoDB connection string):
```
MONGO_URI=mongodb://localhost:27017/internship_matching
PORT=3000 # Optional - if you want to specify a port
```
4. **Run the Application:**
```bash
node index.js
```
5. **Test the API:** Use `curl`, Postman, or any other API client to test the API endpoints. The example `curl` commands provided above are a good starting point.
Important Considerations for a Production Application:
* **Authentication and Authorization:** Implement robust authentication and authorization to protect your API endpoints and data. Consider using JWT (JSON Web Tokens) for authentication.
* **Input Validation:** Add more comprehensive input validation to prevent malicious data from being stored in your database. Libraries like `joi` or `express-validator` can be helpful for this.
* **Rate Limiting:** Implement rate limiting to prevent abuse of your API endpoints.
* **Logging:** Add detailed logging to track API requests, errors, and other important events. Libraries like `winston` or `morgan` can be used for logging.
* **Testing:** Write unit tests and integration tests to ensure the quality and reliability of your code. Frameworks like `mocha` and `jest` can be used for testing.
* **Security:** Follow security best practices to protect your application from common vulnerabilities such as SQL injection, cross-site scripting (XSS), and cross-site request forgery (CSRF). Use tools like `helmet` to secure your Express app.
* **Deployment:** Choose a suitable hosting platform (e.g., AWS, Heroku, Google Cloud) and deploy your application.
* **Database Security:** Secure your MongoDB database by enabling authentication, restricting access to specific IP addresses, and encrypting data at rest.
* **Asynchronous Operations:** For more complex operations (e.g., sending emails), consider using asynchronous processing with queues (e.g., RabbitMQ, Kafka) to improve performance and responsiveness.
This improved example provides a much more solid foundation for building a real-world internship matching portal. Remember to adapt and extend the code to meet your specific requirements.
👁️ Viewed: 5
Comments