-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from BYTE-Club-CCNY/Database
Database
- Loading branch information
Showing
14 changed files
with
623 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,88 @@ | ||
# byte-server | ||
# Byte-server | ||
Server for byte | ||
|
||
# Description | ||
Server is built with Node.js and Express. Provides endpoints for managing a collection of projects, including creating, reading and updating. Exists both a json file and database backup for storing and quering projects | ||
## Description | ||
Server is built with Node.js and Express. Provides endpoints for managing a collection of projects, including creating, reading and updating. Exists both database and a local JSON file backup for storing and quering projects. | ||
|
||
## How to use | ||
Creating, Reading and Updating can be done from the database (default approach) endpoints. Only reading can be done for the local JSON file. | ||
|
||
## Endpoints for DB | ||
|
||
### Get projects | ||
`/projects/get` | ||
|
||
Retrieves all projects in the database and supports additional query params for filtering. | ||
|
||
Filters include: | ||
- **team**: TYPE string(s) | ||
- **cohort**: TYPE string(s) | ||
- **name**: TYPE string(s) | ||
|
||
Filters are stackable, meaning you can do something similar to: | ||
`/projects/get?team=John&cohort=1&team=Jane` | ||
This will return all projects that have John **AND** Jane in their team and are in cohort 1. You can stack as many filters as you want but be aware that the more filters you add, the more specific the query will be, meaning it might return no results. | ||
|
||
### Post new projects | ||
`/projects/add` | ||
|
||
**Please Fill Out All Fields!!!** | ||
These fields must be provided as JSON in the body of the request. | ||
|
||
The schema for projects is defined as follows: | ||
- **name**: TYPE string(s) | ||
- **"short-desc"**: TYPE string(s) | ||
- **"long-desc"**: TYPE string(s) | ||
- **team**: TYPE array of strings | ||
- **link**: TYPE string(s) | ||
- **Image**: TYPE string(s) | ||
- **"tech-stack"**: TYPE array of strings | ||
- **cohort**: TYPE string(s) | ||
- **topic**: TYPE array of strings | ||
|
||
### UPDATE projects | ||
`/projects/update` | ||
|
||
You **MUST** provide the project name you want to update as a query parameter like so: | ||
`/projects/update?name={project_name}` | ||
|
||
You can provide any key value pair you want to update in the body of the request, but it **HAS** to be JSON. This doesn't have to be all the fields, only the ones you want to update. | ||
|
||
Reminder that the schema for projects is defined as follows: | ||
- **name**: TYPE string(s) | ||
- **"short-desc"**: TYPE string(s) | ||
- **"long-desc"**: TYPE string(s) | ||
- **team**: TYPE array of strings | ||
- **link**: TYPE string(s) | ||
- **Image**: TYPE string(s) | ||
- **"tech-stack"**: TYPE array of strings | ||
- **cohort**: TYPE string(s) | ||
- **topic**: TYPE array of strings | ||
|
||
Any mismatch of the schema types (i.e. providing a string when we expect an array) will return an error. | ||
|
||
## Endpoints for Local File | ||
|
||
### Get all projects | ||
`/projects` | ||
|
||
Retrieves all projects from the local JSON file and also supports additional query params for filtering. | ||
|
||
### Get projects based on team members | ||
`/projects?team={member_name}` | ||
|
||
Replace `{member_name}` with a member that is in the project you would like to query. This filter is stackable, meaning you can do something similar to: | ||
`/projects?team=John&team=Jane` | ||
|
||
### Get projects based on cohort | ||
`/projects?cohort={cohort}` | ||
|
||
Replace `{cohort}` with the desired cohort to filter projects. This filter is stackable, meaning you can do something similar to: | ||
`/projects?cohort=1&cohort=2` | ||
|
||
### Get projects based on name | ||
`/projects?name={project_name}` | ||
|
||
Replace `{project_name}` with the desired project name to filter projects. | ||
This filter is stackable, meaning you can do something similar to: | ||
`/projects?name=Website&name=Server` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,20 @@ | ||
import dotenv from 'dotenv'; | ||
import {Client} from 'pg'; | ||
import dotenv from "dotenv"; | ||
import { Client } from "pg"; | ||
dotenv.config(); | ||
|
||
const client = new Client({ | ||
host: process.env.POSTGRESQL_DB_HOST, | ||
user: process.env.POSTGRESQL_DB_USER, | ||
password: process.env.POSTGRESQL_DB_PASSWORD, | ||
database: process.env.POSTGRESQL_DB, | ||
port: process.env.POSTGRESQL_DB_PORT ? parseInt(process.env.POSTGRESQL_DB_PORT) : 5432 | ||
port: process.env.POSTGRESQL_DB_PORT | ||
? parseInt(process.env.POSTGRESQL_DB_PORT) | ||
: 5432, | ||
}); | ||
|
||
client.on("end", () => console.log("Client has disconnected")); | ||
client.on("error", (err) => | ||
console.error("Unexpected error on idle client", err), | ||
); | ||
|
||
export default client; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,20 @@ | ||
import client from './db.config'; | ||
import client from './db.config'; | ||
|
||
const activateDb = async () => { | ||
console.log("Connecting to Database ..."); | ||
let isActive = false; | ||
const getDB = async () => { | ||
console.log("Connecting to Database ..."); | ||
if (isActive) { | ||
console.log("Database already connected"); | ||
return client; | ||
} | ||
try { | ||
await client.connect(); | ||
console.log("Database connected"); | ||
isActive = true; | ||
return client; | ||
} catch (err: any) { | ||
return client; | ||
} | ||
} | ||
|
||
try { | ||
await client.connect(); | ||
console.log("Database connected"); | ||
|
||
return client; | ||
} catch (err: any) { | ||
throw new Error(`Database connection error\n ${err.message}`); | ||
} | ||
} | ||
|
||
export default activateDb; | ||
export default getDB; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import client from "./db.config"; | ||
|
||
async function getDB() { | ||
await client.connect(); | ||
} | ||
|
||
async function checkDB(timeout: number) { | ||
setTimeout(async () => { | ||
try { | ||
await getDB(); | ||
process.exit(0); | ||
} catch (e: any) { | ||
console.error("Error Connecting to DB:", e.message); | ||
process.exit(1); | ||
} | ||
}, timeout); | ||
} | ||
|
||
const args: string[] = process.argv; | ||
const timeout: number = parseInt(args[2]); | ||
|
||
await checkDB(timeout); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { spawn } from "child_process"; | ||
|
||
export function secondsToMs(d: number) { | ||
return d * 1000; | ||
} | ||
|
||
// threading should happen at top level of server "setInterval" | ||
async function checkDB(TIMEOUT: number): Promise<boolean> { | ||
return new Promise((resolve, reject) => { | ||
let dbAval: boolean = false; | ||
|
||
const database = spawn("bun", ["dbCheck.ts", TIMEOUT.toString()]); | ||
|
||
database.stdout.on("data", (data) => { | ||
console.log("Output from dbCheck.ts:", data.toString()); | ||
}); | ||
|
||
database.on("exit", (code) => { | ||
if (code === 0) { | ||
dbAval = true; | ||
} else { | ||
dbAval = false; | ||
} | ||
resolve(dbAval); | ||
}); | ||
|
||
database.on("error", (error) => { | ||
console.error(error); | ||
reject(error); | ||
}); | ||
}); | ||
} | ||
|
||
export default checkDB; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import getDB from "../db"; | ||
import logger from "../utils/logger"; | ||
|
||
const connectDB = async (req: any, res: any, next: any) => { | ||
try { | ||
req.client = await getDB(); | ||
next(); | ||
} catch (err: any) { | ||
logger.info(err.message); | ||
next("route"); | ||
} | ||
} | ||
|
||
export default connectDB; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
//validate all fields and their types | ||
function validating( | ||
keys: string[], | ||
values: any, | ||
requiredFields: { [key: string]: string }, | ||
res: any, | ||
) { | ||
for (let i = 0; i < values.length; i++) { | ||
//initial check if the field is a required field | ||
if (!(keys[i] in requiredFields)) { | ||
return res | ||
.status(400) | ||
.json({ | ||
message: `Please insert a valid field name, ${keys[i]} is invalid`, | ||
}); | ||
} | ||
//check for the correct typing | ||
if (typeof values[i] !== requiredFields[keys[i]]) { | ||
return res | ||
.status(400) | ||
.json({ | ||
message: `Please insert the correct typing for ${keys[i]}, it should be a ${requiredFields[keys[i]] === "object" ? "array of strings" : requiredFields[keys[i]]}!`, | ||
}); | ||
} | ||
} | ||
// if no response is sent meaning all validations passed, return false at the end of the function | ||
return false; | ||
} | ||
|
||
const validate = (req: any, res: any, next: any) => { | ||
const requiredFields = { | ||
name: "string", | ||
"short-desc": "string", | ||
"long-desc": "string", | ||
team: "object", | ||
link: "string", | ||
image: "string", | ||
"tech-stack": "object", | ||
cohort: "string", | ||
topic: "object", | ||
}; | ||
const values = Object.values(req.body); | ||
const keys = Object.keys(req.body); | ||
|
||
if (req.method === "POST") { | ||
//initial check for empty request body | ||
if (Object.keys(req.body).length === 0) { | ||
return res | ||
.status(400) | ||
.json({ | ||
message: "Please insert a object with all required fields!", | ||
}); | ||
} | ||
if (keys.length !== 9) { | ||
return res | ||
.status(400) | ||
.json({ | ||
message: | ||
"Please insert all required fields, you are missing some fields!", | ||
}); | ||
} else { | ||
if (validating(keys, values, requiredFields, res)) { | ||
return; | ||
} | ||
} | ||
} else { | ||
//initial check for empty request body | ||
if (Object.keys(req.body).length === 0) { | ||
return res | ||
.status(400) | ||
.json({ message: "Please insert a object to update!" }); | ||
} else { | ||
if (validating(keys, values, requiredFields, res)) { | ||
return; | ||
} | ||
} | ||
} | ||
next(); | ||
}; | ||
|
||
export default validate; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.