Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PORT=
File renamed without changes.
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# API Documentation

This documentation provides an overview of the available routes and data models for the Cohort Tools API.

Throughout the project, you should use this documentation as a reference and a guide. Refer to it whenever you need information or more details on how to implement the routes or model your database.

<br>

## Routes

In this section, you will find detailed information about the different routes available in the API.
The API offers a variety of routes to work with *cohort* and *student* documents. Each route is associated with a specific HTTP verb and URL, allowing you to perform CRUD (Create, Read, Update, and Delete) actions on the data.

<br>

#### Cohort routes

| HTTP verb | URL | Request body | Action |
| --------- | -------------------------- | ------------ | -------------------------------------- |
| GET | `/api/cohorts` | (empty) | Returns all the cohorts in JSON format |
| GET | `/api/cohorts/:cohortId` | (empty) | Returns the specified cohort by id |
| POST | `/api/cohorts` | JSON | Creates a new cohort |
| PUT | `/api/cohorts/:cohortId` | JSON | Updates the specified cohort by id |
| DELETE | `/api/cohorts/:cohortId` | (empty) | Deletes the specified cohort by id |


<br>

#### Student routes

| HTTP verb | URL | Request body | Action |
| --------- | --------------------------------- | ------------ | -------------------------------------------------------------- |
| GET | `/api/students` | (empty) | Returns all the students in JSON format |
| GET | `/api/students/cohort/:cohortId` | (empty) | Returns all the students of a specified cohort in JSON format |
| GET | `/api/students/:studentId` | (empty) | Returns the specified student by id |
| POST | `/api/students` | JSON | Creates a new student **with their respective cohort id** |
| PUT | `/api/students/:studentId` | JSON | Updates the specified student by id |
| DELETE | `/api/students/:studentId` | (empty) | Deletes the specified cohort by id |


<hr>

<br>

## Models

The *Models* section holds information about the data models for your database. It outlines the structure of the documents in the database, providing you with a clear understanding of how your data should be organized.

<br>

#### Cohort Model

| Field | Data Type | Description |
|----------------|------------------|---------------------------------------------|
| `cohortSlug` | *`String`* | Unique identifier for the cohort. Required. |
| `cohortName` | *`String`* | Name of the cohort. Required. |
| `program` | *`String`* | Program/course name. Allowed values: "Web Dev", "UX/UI", "Data Analytics", "Cybersecurity". |
| `format` | *`String`* | Format of the cohort. Allowed values: "Full Time", "Part Time". |
| `campus` | *`String`* | Campus location. Allowed values: "Madrid", "Barcelona", "Miami", "Paris", "Berlin", "Amsterdam", "Lisbon", "Remote". |
| `startDate` | *`Date`* | Start date of the cohort. Default: Current date. |
| `endDate` | *`Date`* | End date of the cohort. |
| `inProgress` | *`Boolean`* | Indicates if the cohort is currently in progress. Default: false. |
| `programManager` | *`String`* | Name of the program manager. Required. |
| `leadTeacher` | *`String`* | Name of the lead teacher. Required. |
| `totalHours` | *`Number`* | Total hours of the cohort program. Default: 360. |


<br>

#### Student Model

| Field | Data Type | Description |
|--------------|--------------------------------------|----------------------------------------------|
| `firstName` | *`String`* | First name of the student. Required. |
| `lastName` | *`String`* | Last name of the student. Required. |
| `email` | *`String`* | Email address of the student. Required, unique. |
| `phone` | *`String`* | Phone number of the student. Required. |
| `linkedinUrl` | *`String`* | URL to the student's LinkedIn profile. Default: Empty string. |
| `languages` | *`Array`* of Strings | Spoken languages of the student. Allowed values: "English", "Spanish", "French", "German", "Portuguese", "Dutch", "Other". |
| `program` | *`String`* | Type of program the student is enrolled in. Allowed values: "Web Dev", "UX/UI", "Data Analytics", "Cybersecurity". |
| `background` | *`String`* | Background information about the student. Default: Empty. |
| `image` | *`String`* | URL to the student's profile image. Default: https://i.imgur.com/r8bo8u7.png . |
| `cohort` | *`ObjectId`*, | Reference *_id* of the cohort the student belongs to. |
| `projects` | *`Array`* | Array of the student's projects. |


<br>

247 changes: 247 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
process.loadEnvFile();
// Express framework for creating the server and routes
const express = require("express");
// STATIC DATA
// CREATE EXPRESS APPLICATION
const app = express();

// Morgan logs HTTP requests in the terminal
// const morgan = require("morgan");

// Helps read cookies sent by the browser
const cookieParser = require("cookie-parser");

// Mongoose allows Node.js to communicate with MongoDB
// const mongoose = require("mongoose");

// Enables communication between frontend and backend on different ports/domains
const cors = require("cors");

//* DEFINE SERVER PORT
// The backend server will run on port 5005
// const PORT = 5005;

// IMPORT DATABASE MODELS
// These models represent collections in MongoDB
const Cohort = require("./models/Cohort.model");
const Student = require("./models/Student.model");

//* MIDDLEWARE
// Research Team - Set up CORS middleware here:
const config = require("./config");
config(app);

// Enable CORS so frontend apps can access this API
// app.use(cors());

//* Connect to MongoDB database
//We import DB from its dedicated folder (db)
const connectDB = require("./db");
app.use(async (req, res, next) => {
await connectDB();
next();
});
// mongoose.connect("mongodb://127.0.0.1:27017/cohort-tools-api")
// Runs if connection is successful
// .then((x) => console.log(`Connected to Database: "${x.connections[0].name}"`))

// Runs if there is a database connection error
// .catch((err) => console.error("Error connecting to MongoDB", err));

// Parse incoming JSON data from requests
app.use(express.json());

// Log requests in the terminal
// app.use(morgan("dev"));

// Makes files inside the "public" folder accessible
app.use(express.static("public"));

// Parses URL-encoded form data
// Useful when data comes from HTML forms
app.use(express.urlencoded({ extended: false }));

// Allows reading cookies from requests
app.use(cookieParser());

// ROUTES - https://expressjs.com/en/starter/basic-routing.html
// Devs Team - Start working on the routes here:
//* TEST ROUTE
// Sends the docs.html file when user visits /docs
app.get("/docs", (req, res) => {
// __dirname = current folder location
// res.sendFile(__dirname + "/views/docs.html");
res.status(200).json({ message: "looking perfect already" });
});

app.get("/api/test", (req, res, next) => {
console.log(req.body); // when we receive a lot of data, usually for document creation or updates
console.log(req.query); // when we are trying to search or filter data
console.log(req.params); // when we are passings ids, usually for getting the details of a specific document, updating or deleting a specific document

res.status(200).json({ message: "perfectly working fine" });
});

app.get("/", (req, res, next) => {
res.json("Testing");
});

// GET ALL COHORTS
// Route: GET /cohorts
app.get("/api/cohorts", async (req, res) => {
try {
const response = await Cohort.find({ awardsWon: { $gte: 200 } }).select({
name: 1,
awardsWon: 1,
});
console.log(response);

if (response.length === 0) {
res.status(204).json(response);
} else {
res.status(200).json(response);
}
} catch (error) {
console.log(error);
}
});

// this is to create a new student
app.post("/cohorts", async (req, res) => {
try {
const newCohort = {
cohortSlug: req.body.cohortSlug,
cohortName: req.body.cohortName,
program: req.body.program,
campus: req.body.campus,
startDate: req.body.startDate,
endDate: req.body.endDate,
};
const response = await Cohort.create(newCohort);
res.status(200).json(response);
console.log("new cohort created");
} catch (error) {
console.log(error);
}
});

// this is to update the student
app.patch("/cohorts/:cohortId", async (req, res) => {
try {
const updatedCohort = {
cohortSlug: req.body.cohortSlug,
cohortName: req.body.cohortName,
program: req.body.program,
campus: req.body.campus,
startDate: req.body.startDate,
endDate: req.body.endDate,
};
const response = await Cohort.findByIdAndUpdate(
req.params.cohortId,
updatedCohort,
{ new: true },
);
res.status(200).json(response);
console.log("new cohort updated");
} catch (error) {
console.log(error);
}
});

// this is to delete a student
app.delete("/cohorts/:cohortId", async (req, res) => {
try {
const response = await Cohort.findByIdAndDelete(req.params.cohortId);
res.sendStatus(200);
console.log("cohort deleted");
} catch (error) {
console.log(error);
}
});

// GET ALL STUDENTS
// Route: GET /students
app.get("/", (req, res) => {
try {
res.json({ message: "all is good you are connecting to " });
} catch (err) {
console.log(error);
}
});
app.get("/students", async (req, res) => {
try {
const response = await Student.find();
console.log("Retrieved students ->", response);
res.status(200).json(response);
} catch (error) {
console.log(error);
}
});

// this is to create a new student
app.post("/students", async (req, res) => {
try {
const newStudent = {
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
phone: req.body.phone,
linkedinUrl: req.body.linkedinUrl,
program: req.body.proram,
background: req.body.background,
image: req.body.image,
cohort: req.body.cohort,
};
const response = await Student.create(newStudent);
res.status(200).json(response);
console.log("new student created");
} catch (error) {
console.log(error);
}
});

// this is to update the student
app.patch("/students/:studentId", async (req, res) => {
try {
const updatedStudent = {
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
phone: req.body.phone,
linkedinUrl: req.body.linkedinUrl,
program: req.body.proram,
background: req.body.background,
image: req.body.image,
};
const response = await Student.findByIdAndUpdate(
req.params.studentId,
updatedStudent,
{ new: true },
);
res.status(200).json(response);
console.log("new student updated");
} catch (error) {
console.log(error);
}
});

// this is to delete a student
app.delete("/students/:studentId", async (req, res) => {
try {
const response = await Student.findByIdAndDelete(req.params.studentId);
res.sendStatus(200);
console.log("student deleted");
} catch (error) {
console.log(error);
}
});

const indexRouter = require("./routes/index.routes");
app.use("/api", indexRouter);
// server listen & PORT

// Start server
const PORT = process.env.PORT || 5006;
app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
});
26 changes: 26 additions & 0 deletions config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const express = require("express");
const logger = require("morgan");
const cors = require("cors");

// Middleware configuration | Enables Express to trust reverse proxies (e.g., when deployed behind services like Heroku or Vercel)
function config(app) {
app.set("trust proxy", 1);

// CORS to allow requests only from the specified origin
app.use(
cors({
origin: [process.env.ORIGIN],
}),
);

// Logs requests in the development environment
app.use(logger("dev"));

// Parses incoming JSON requests
app.use(express.json());

// Parses incoming request bodies with URL-encoded data (form submissions)
app.use(express.urlencoded({ extended: false }));
}

module.exports = config;
18 changes: 18 additions & 0 deletions db/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const mongoose = require("mongoose");

// Checks if a DB connection is already present. Prevents duplicate connections on serverless deployments like Vercel.
async function connectDB() {
if (mongoose.connection.readyState === 1) {
return;
}

try {
const response = await mongoose.connect(process.env.MONGODB_URI);
const dbName = response.connections[0].name;
console.log(`Connected to Mongo! Database name: "${dbName}"`);
} catch (err) {
console.error("Error connecting to mongo: ", err);
}
}

module.exports = connectDB;
12 changes: 12 additions & 0 deletions models/Cohort.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const mongoose = require("mongoose");

const cohortSchema = new mongoose.Schema({
cohortSlug: String,
cohortName: String,
program: String,
campus: String,
startDate: Date,
endDate: Date,
});

module.exports = mongoose.model("Cohort", cohortSchema);
Loading